github.com/koko1123/flow-go-1@v0.29.6/fvm/bootstrap.go (about) 1 package fvm 2 3 import ( 4 "fmt" 5 "math" 6 7 "github.com/onflow/cadence" 8 "github.com/onflow/flow-core-contracts/lib/go/contracts" 9 10 "github.com/koko1123/flow-go-1/fvm/blueprints" 11 "github.com/koko1123/flow-go-1/fvm/derived" 12 "github.com/koko1123/flow-go-1/fvm/environment" 13 "github.com/koko1123/flow-go-1/fvm/errors" 14 "github.com/koko1123/flow-go-1/fvm/meter" 15 "github.com/koko1123/flow-go-1/fvm/state" 16 "github.com/koko1123/flow-go-1/model/flow" 17 "github.com/koko1123/flow-go-1/module/epochs" 18 ) 19 20 var ( 21 DefaultAccountCreationFee = mustParseUFix64( 22 "account creation fee", 23 "0.00100000") 24 25 DefaultMinimumStorageReservation = mustParseUFix64( 26 "minimum storage reservation", 27 "0.00100000") 28 29 DefaultStorageMBPerFLOW = mustParseUFix64( 30 "storage mb per flow", 31 "100.00000000") 32 33 // DefaultTransactionFees are the default transaction fee parameters if 34 // transaction fees are on. Surge factor is 1.0, inclusion effort cost is 35 // 0.0001 (because the static inclusion effort is 1.0) and execution effort 36 // cost is 0.0 because dynamic execution fees are off. If they are off 37 // (which is the default behaviour) that means the transaction fees are 0.0. 38 DefaultTransactionFees = BootstrapProcedureFeeParameters{ 39 SurgeFactor: mustParseUFix64("fee surge factor", "1.0"), 40 InclusionEffortCost: mustParseUFix64( 41 "fee inclusion effort cost", 42 "0.00001"), 43 ExecutionEffortCost: mustParseUFix64( 44 "fee execution effort cost", 45 "0.0"), 46 } 47 ) 48 49 func mustParseUFix64(name string, valueString string) cadence.UFix64 { 50 value, err := cadence.NewUFix64(valueString) 51 if err != nil { 52 panic(fmt.Errorf("invalid default %s: %w", name, err)) 53 } 54 return value 55 } 56 57 // A BootstrapProcedure is an invokable that can be used to bootstrap the ledger state 58 // with the default accounts and contracts required by the Flow virtual machine. 59 type BootstrapProcedure struct { 60 BootstrapParams 61 } 62 63 type BootstrapParams struct { 64 rootBlock *flow.Header 65 66 // genesis parameters 67 accountKeys BootstrapAccountKeys 68 initialTokenSupply cadence.UFix64 69 70 accountCreationFee cadence.UFix64 71 minimumStorageReservation cadence.UFix64 72 storagePerFlow cadence.UFix64 73 restrictedAccountCreationEnabled cadence.Bool 74 75 // TODO: restrictedContractDeployment should be a bool after RestrictedDeploymentEnabled is removed from the context 76 // restrictedContractDeployment of nil means that the contract deployment is taken from the fvm Context instead of from the state. 77 // This can be used to mimic behaviour on chain before the restrictedContractDeployment is set with a service account transaction. 78 restrictedContractDeployment *bool 79 80 transactionFees BootstrapProcedureFeeParameters 81 executionEffortWeights meter.ExecutionEffortWeights 82 executionMemoryWeights meter.ExecutionMemoryWeights 83 // executionMemoryLimit of 0 means that it won't be set in the state. The FVM will use the default value from the context. 84 executionMemoryLimit uint64 85 86 // config values for epoch smart-contracts 87 epochConfig epochs.EpochConfig 88 89 // list of initial network participants for whom we will create/stake flow 90 // accounts and retrieve epoch-related resources 91 identities flow.IdentityList 92 } 93 94 type BootstrapAccountKeys struct { 95 ServiceAccountPublicKeys []flow.AccountPublicKey 96 FungibleTokenAccountPublicKeys []flow.AccountPublicKey 97 FlowTokenAccountPublicKeys []flow.AccountPublicKey 98 FlowFeesAccountPublicKeys []flow.AccountPublicKey 99 NodeAccountPublicKeys []flow.AccountPublicKey 100 } 101 102 type BootstrapProcedureFeeParameters struct { 103 SurgeFactor cadence.UFix64 104 InclusionEffortCost cadence.UFix64 105 ExecutionEffortCost cadence.UFix64 106 } 107 108 type BootstrapProcedureOption func(*BootstrapProcedure) *BootstrapProcedure 109 110 func WithInitialTokenSupply(supply cadence.UFix64) BootstrapProcedureOption { 111 return func(bp *BootstrapProcedure) *BootstrapProcedure { 112 bp.initialTokenSupply = supply 113 return bp 114 } 115 } 116 117 // WithBootstrapAccountKeys sets the public keys of the accounts that will be created during bootstrapping 118 // by default all accounts are created with the ServiceAccountPublicKey specified when calling `Bootstrap`. 119 func WithBootstrapAccountKeys(keys BootstrapAccountKeys) BootstrapProcedureOption { 120 return func(bp *BootstrapProcedure) *BootstrapProcedure { 121 bp.accountKeys = keys 122 return bp 123 } 124 } 125 126 func WithAccountCreationFee(fee cadence.UFix64) BootstrapProcedureOption { 127 return func(bp *BootstrapProcedure) *BootstrapProcedure { 128 bp.accountCreationFee = fee 129 return bp 130 } 131 } 132 133 func WithTransactionFee(fees BootstrapProcedureFeeParameters) BootstrapProcedureOption { 134 return func(bp *BootstrapProcedure) *BootstrapProcedure { 135 bp.transactionFees = fees 136 return bp 137 } 138 } 139 140 func WithExecutionEffortWeights(weights meter.ExecutionEffortWeights) BootstrapProcedureOption { 141 return func(bp *BootstrapProcedure) *BootstrapProcedure { 142 bp.executionEffortWeights = weights 143 return bp 144 } 145 } 146 147 func WithExecutionMemoryWeights(weights meter.ExecutionMemoryWeights) BootstrapProcedureOption { 148 return func(bp *BootstrapProcedure) *BootstrapProcedure { 149 bp.executionMemoryWeights = weights 150 return bp 151 } 152 } 153 154 func WithExecutionMemoryLimit(limit uint64) BootstrapProcedureOption { 155 return func(bp *BootstrapProcedure) *BootstrapProcedure { 156 bp.executionMemoryLimit = limit 157 return bp 158 } 159 } 160 161 func WithMinimumStorageReservation(reservation cadence.UFix64) BootstrapProcedureOption { 162 return func(bp *BootstrapProcedure) *BootstrapProcedure { 163 bp.minimumStorageReservation = reservation 164 return bp 165 } 166 } 167 168 func WithEpochConfig(epochConfig epochs.EpochConfig) BootstrapProcedureOption { 169 return func(bp *BootstrapProcedure) *BootstrapProcedure { 170 bp.epochConfig = epochConfig 171 return bp 172 } 173 } 174 175 func WithRootBlock(rootBlock *flow.Header) BootstrapProcedureOption { 176 return func(bp *BootstrapProcedure) *BootstrapProcedure { 177 bp.rootBlock = rootBlock 178 return bp 179 } 180 } 181 182 func WithIdentities(identities flow.IdentityList) BootstrapProcedureOption { 183 return func(bp *BootstrapProcedure) *BootstrapProcedure { 184 bp.identities = identities 185 return bp 186 } 187 } 188 189 func WithStorageMBPerFLOW(ratio cadence.UFix64) BootstrapProcedureOption { 190 return func(bp *BootstrapProcedure) *BootstrapProcedure { 191 bp.storagePerFlow = ratio 192 return bp 193 } 194 } 195 196 func WithRestrictedAccountCreationEnabled(enabled cadence.Bool) BootstrapProcedureOption { 197 return func(bp *BootstrapProcedure) *BootstrapProcedure { 198 bp.restrictedAccountCreationEnabled = enabled 199 return bp 200 } 201 } 202 203 func WithRestrictedContractDeployment(restricted *bool) BootstrapProcedureOption { 204 return func(bp *BootstrapProcedure) *BootstrapProcedure { 205 bp.restrictedContractDeployment = restricted 206 return bp 207 } 208 } 209 210 // Bootstrap returns a new BootstrapProcedure instance configured with the provided 211 // genesis parameters. 212 func Bootstrap( 213 serviceAccountPublicKey flow.AccountPublicKey, 214 opts ...BootstrapProcedureOption, 215 ) *BootstrapProcedure { 216 bootstrapProcedure := &BootstrapProcedure{ 217 BootstrapParams: BootstrapParams{ 218 accountKeys: BootstrapAccountKeys{ 219 ServiceAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey}, 220 FungibleTokenAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey}, 221 FlowTokenAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey}, 222 NodeAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey}, 223 }, 224 transactionFees: BootstrapProcedureFeeParameters{0, 0, 0}, 225 epochConfig: epochs.DefaultEpochConfig(), 226 }, 227 } 228 229 for _, applyOption := range opts { 230 bootstrapProcedure = applyOption(bootstrapProcedure) 231 } 232 return bootstrapProcedure 233 } 234 235 func (b *BootstrapProcedure) NewExecutor( 236 ctx Context, 237 txnState *state.TransactionState, 238 _ *derived.DerivedTransactionData, 239 ) ProcedureExecutor { 240 return newBootstrapExecutor(b.BootstrapParams, ctx, txnState) 241 } 242 243 func (proc *BootstrapProcedure) ComputationLimit(_ Context) uint64 { 244 return math.MaxUint64 245 } 246 247 func (proc *BootstrapProcedure) MemoryLimit(_ Context) uint64 { 248 return math.MaxUint64 249 } 250 251 func (proc *BootstrapProcedure) ShouldDisableMemoryAndInteractionLimits(_ Context) bool { 252 return true 253 } 254 255 func (BootstrapProcedure) Type() ProcedureType { 256 return BootstrapProcedureType 257 } 258 259 func (proc *BootstrapProcedure) InitialSnapshotTime() derived.LogicalTime { 260 return 0 261 } 262 263 func (proc *BootstrapProcedure) ExecutionTime() derived.LogicalTime { 264 return 0 265 } 266 267 type bootstrapExecutor struct { 268 BootstrapParams 269 270 ctx Context 271 txnState *state.TransactionState 272 273 accountCreator environment.BootstrapAccountCreator 274 } 275 276 func newBootstrapExecutor( 277 params BootstrapParams, 278 ctx Context, 279 txnState *state.TransactionState, 280 ) *bootstrapExecutor { 281 return &bootstrapExecutor{ 282 BootstrapParams: params, 283 ctx: NewContextFromParent( 284 ctx, 285 WithContractDeploymentRestricted(false)), 286 txnState: txnState, 287 } 288 } 289 290 func (b *bootstrapExecutor) Cleanup() { 291 // Do nothing. 292 } 293 294 func (b *bootstrapExecutor) Preprocess() error { 295 // Do nothing. 296 return nil 297 } 298 299 func (b *bootstrapExecutor) Execute() error { 300 b.rootBlock = flow.Genesis(flow.ChainID(b.ctx.Chain.String())).Header 301 302 // initialize the account addressing state 303 b.accountCreator = environment.NewBootstrapAccountCreator( 304 b.txnState, 305 b.ctx.Chain, 306 environment.NewAccounts(b.txnState)) 307 308 service := b.createServiceAccount() 309 310 b.deployContractAuditVouchers(service) 311 fungibleToken := b.deployFungibleToken() 312 flowToken := b.deployFlowToken(service, fungibleToken) 313 storageFees := b.deployStorageFees(service, fungibleToken, flowToken) 314 feeContract := b.deployFlowFees(service, fungibleToken, flowToken, storageFees) 315 316 if b.initialTokenSupply > 0 { 317 b.mintInitialTokens(service, fungibleToken, flowToken, b.initialTokenSupply) 318 } 319 320 b.deployServiceAccount(service, fungibleToken, flowToken, feeContract) 321 322 b.setupParameters( 323 service, 324 b.accountCreationFee, 325 b.minimumStorageReservation, 326 b.storagePerFlow, 327 b.restrictedAccountCreationEnabled, 328 ) 329 330 b.setupFees( 331 service, 332 feeContract, 333 b.transactionFees.SurgeFactor, 334 b.transactionFees.InclusionEffortCost, 335 b.transactionFees.ExecutionEffortCost, 336 ) 337 338 b.setContractDeploymentRestrictions(service, b.restrictedContractDeployment) 339 340 b.setupExecutionWeights(service) 341 342 b.setupStorageForServiceAccounts(service, fungibleToken, flowToken, feeContract) 343 344 b.createMinter(service, flowToken) 345 346 b.deployDKG(service) 347 348 b.deployQC(service) 349 350 b.deployIDTableStaking(service, fungibleToken, flowToken, feeContract) 351 352 // set the list of nodes which are allowed to stake in this network 353 b.setStakingAllowlist(service, b.identities.NodeIDs()) 354 355 b.deployEpoch(service, fungibleToken, flowToken, feeContract) 356 357 // deploy staking proxy contract to the service account 358 b.deployStakingProxyContract(service) 359 360 // deploy locked tokens contract to the service account 361 b.deployLockedTokensContract(service, fungibleToken, flowToken) 362 363 // deploy staking collection contract to the service account 364 b.deployStakingCollection(service, fungibleToken, flowToken) 365 366 b.registerNodes(service, fungibleToken, flowToken) 367 368 return nil 369 } 370 371 func (b *bootstrapExecutor) createAccount(publicKeys []flow.AccountPublicKey) flow.Address { 372 address, err := b.accountCreator.CreateBootstrapAccount(publicKeys) 373 if err != nil { 374 panic(fmt.Sprintf("failed to create account: %s", err)) 375 } 376 377 return address 378 } 379 380 func (b *bootstrapExecutor) createServiceAccount() flow.Address { 381 address, err := b.accountCreator.CreateBootstrapAccount( 382 b.accountKeys.ServiceAccountPublicKeys) 383 if err != nil { 384 panic(fmt.Sprintf("failed to create service account: %s", err)) 385 } 386 387 return address 388 } 389 390 func (b *bootstrapExecutor) deployFungibleToken() flow.Address { 391 fungibleToken := b.createAccount(b.accountKeys.FungibleTokenAccountPublicKeys) 392 393 txError, err := b.invokeMetaTransaction( 394 b.ctx, 395 Transaction( 396 blueprints.DeployFungibleTokenContractTransaction(fungibleToken), 397 0), 398 ) 399 panicOnMetaInvokeErrf("failed to deploy fungible token contract: %s", txError, err) 400 return fungibleToken 401 } 402 403 func (b *bootstrapExecutor) deployFlowToken(service, fungibleToken flow.Address) flow.Address { 404 flowToken := b.createAccount(b.accountKeys.FlowTokenAccountPublicKeys) 405 txError, err := b.invokeMetaTransaction( 406 b.ctx, 407 Transaction( 408 blueprints.DeployFlowTokenContractTransaction( 409 service, 410 fungibleToken, 411 flowToken), 412 0), 413 ) 414 panicOnMetaInvokeErrf("failed to deploy Flow token contract: %s", txError, err) 415 return flowToken 416 } 417 418 func (b *bootstrapExecutor) deployFlowFees(service, fungibleToken, flowToken, storageFees flow.Address) flow.Address { 419 flowFees := b.createAccount(b.accountKeys.FlowFeesAccountPublicKeys) 420 421 txError, err := b.invokeMetaTransaction( 422 b.ctx, 423 Transaction( 424 blueprints.DeployTxFeesContractTransaction( 425 service, 426 fungibleToken, 427 flowToken, 428 storageFees, 429 flowFees, 430 ), 431 0), 432 ) 433 panicOnMetaInvokeErrf("failed to deploy fees contract: %s", txError, err) 434 return flowFees 435 } 436 437 func (b *bootstrapExecutor) deployStorageFees(service, fungibleToken, flowToken flow.Address) flow.Address { 438 contract := contracts.FlowStorageFees( 439 fungibleToken.HexWithPrefix(), 440 flowToken.HexWithPrefix(), 441 ) 442 443 // deploy storage fees contract on the service account 444 txError, err := b.invokeMetaTransaction( 445 b.ctx, 446 Transaction( 447 blueprints.DeployStorageFeesContractTransaction( 448 service, 449 contract), 450 0), 451 ) 452 panicOnMetaInvokeErrf("failed to deploy storage fees contract: %s", txError, err) 453 return service 454 } 455 456 // deployContractAuditVouchers deploys audit vouchers contract to the service account 457 func (b *bootstrapExecutor) deployContractAuditVouchers(service flow.Address) { 458 contract := contracts.FlowContractAudits() 459 460 txError, err := b.invokeMetaTransaction( 461 b.ctx, 462 Transaction( 463 blueprints.DeployContractTransaction( 464 service, 465 contract, 466 "FlowContractAudits"), 467 0), 468 ) 469 panicOnMetaInvokeErrf("failed to deploy contract audit vouchers contract: %s", txError, err) 470 } 471 472 func (b *bootstrapExecutor) createMinter(service, flowToken flow.Address) { 473 txError, err := b.invokeMetaTransaction( 474 b.ctx, 475 Transaction( 476 blueprints.CreateFlowTokenMinterTransaction( 477 service, 478 flowToken), 479 0), 480 ) 481 panicOnMetaInvokeErrf("failed to create flow token minter: %s", txError, err) 482 } 483 484 func (b *bootstrapExecutor) deployDKG(service flow.Address) { 485 contract := contracts.FlowDKG() 486 txError, err := b.invokeMetaTransaction( 487 b.ctx, 488 Transaction( 489 blueprints.DeployContractTransaction(service, contract, "FlowDKG"), 490 0, 491 ), 492 ) 493 panicOnMetaInvokeErrf("failed to deploy DKG contract: %s", txError, err) 494 } 495 496 func (b *bootstrapExecutor) deployQC(service flow.Address) { 497 contract := contracts.FlowQC() 498 txError, err := b.invokeMetaTransaction( 499 b.ctx, 500 Transaction( 501 blueprints.DeployContractTransaction(service, contract, "FlowClusterQC"), 502 0, 503 ), 504 ) 505 panicOnMetaInvokeErrf("failed to deploy QC contract: %s", txError, err) 506 } 507 508 func (b *bootstrapExecutor) deployIDTableStaking(service, fungibleToken, flowToken, flowFees flow.Address) { 509 510 contract := contracts.FlowIDTableStaking( 511 fungibleToken.HexWithPrefix(), 512 flowToken.HexWithPrefix(), 513 flowFees.HexWithPrefix(), 514 true) 515 516 txError, err := b.invokeMetaTransaction( 517 b.ctx, 518 Transaction( 519 blueprints.DeployIDTableStakingTransaction(service, 520 contract, 521 b.epochConfig.EpochTokenPayout, 522 b.epochConfig.RewardCut), 523 0, 524 ), 525 ) 526 panicOnMetaInvokeErrf("failed to deploy IDTableStaking contract: %s", txError, err) 527 } 528 529 func (b *bootstrapExecutor) deployEpoch(service, fungibleToken, flowToken, flowFees flow.Address) { 530 531 contract := contracts.FlowEpoch( 532 fungibleToken.HexWithPrefix(), 533 flowToken.HexWithPrefix(), 534 service.HexWithPrefix(), 535 service.HexWithPrefix(), 536 service.HexWithPrefix(), 537 flowFees.HexWithPrefix(), 538 ) 539 540 context := NewContextFromParent(b.ctx, 541 WithBlockHeader(b.rootBlock), 542 WithBlocks(&environment.NoopBlockFinder{}), 543 ) 544 545 txError, err := b.invokeMetaTransaction( 546 context, 547 Transaction( 548 blueprints.DeployEpochTransaction(service, contract, b.epochConfig), 549 0, 550 ), 551 ) 552 panicOnMetaInvokeErrf("failed to deploy Epoch contract: %s", txError, err) 553 } 554 555 func (b *bootstrapExecutor) deployServiceAccount(service, fungibleToken, flowToken, feeContract flow.Address) { 556 contract := contracts.FlowServiceAccount( 557 fungibleToken.HexWithPrefix(), 558 flowToken.HexWithPrefix(), 559 feeContract.HexWithPrefix(), 560 service.HexWithPrefix(), 561 ) 562 563 txError, err := b.invokeMetaTransaction( 564 b.ctx, 565 Transaction( 566 blueprints.DeployContractTransaction( 567 service, 568 contract, 569 "FlowServiceAccount"), 570 0), 571 ) 572 panicOnMetaInvokeErrf("failed to deploy service account contract: %s", txError, err) 573 } 574 575 func (b *bootstrapExecutor) mintInitialTokens( 576 service, fungibleToken, flowToken flow.Address, 577 initialSupply cadence.UFix64, 578 ) { 579 txError, err := b.invokeMetaTransaction( 580 b.ctx, 581 Transaction( 582 blueprints.MintFlowTokenTransaction( 583 fungibleToken, 584 flowToken, 585 service, 586 initialSupply), 587 0), 588 ) 589 panicOnMetaInvokeErrf("failed to mint initial token supply: %s", txError, err) 590 } 591 592 func (b *bootstrapExecutor) setupParameters( 593 service flow.Address, 594 addressCreationFee, 595 minimumStorageReservation, 596 storagePerFlow cadence.UFix64, 597 restrictedAccountCreationEnabled cadence.Bool, 598 ) { 599 txError, err := b.invokeMetaTransaction( 600 b.ctx, 601 Transaction( 602 blueprints.SetupParametersTransaction( 603 service, 604 addressCreationFee, 605 minimumStorageReservation, 606 storagePerFlow, 607 restrictedAccountCreationEnabled, 608 ), 609 0), 610 ) 611 panicOnMetaInvokeErrf("failed to setup parameters: %s", txError, err) 612 } 613 614 func (b *bootstrapExecutor) setupFees(service, flowFees flow.Address, surgeFactor, inclusionEffortCost, executionEffortCost cadence.UFix64) { 615 txError, err := b.invokeMetaTransaction( 616 b.ctx, 617 Transaction( 618 blueprints.SetupFeesTransaction( 619 service, 620 flowFees, 621 surgeFactor, 622 inclusionEffortCost, 623 executionEffortCost, 624 ), 625 0), 626 ) 627 panicOnMetaInvokeErrf("failed to setup fees: %s", txError, err) 628 } 629 630 func (b *bootstrapExecutor) setupExecutionWeights(service flow.Address) { 631 // if executionEffortWeights were not set skip this part and just use the defaults. 632 if b.executionEffortWeights != nil { 633 b.setupExecutionEffortWeights(service) 634 } 635 // if executionMemoryWeights were not set skip this part and just use the defaults. 636 if b.executionMemoryWeights != nil { 637 b.setupExecutionMemoryWeights(service) 638 } 639 if b.executionMemoryLimit != 0 { 640 b.setExecutionMemoryLimitTransaction(service) 641 } 642 } 643 644 func (b *bootstrapExecutor) setupExecutionEffortWeights(service flow.Address) { 645 weights := b.executionEffortWeights 646 647 uintWeights := make(map[uint]uint64, len(weights)) 648 for i, weight := range weights { 649 uintWeights[uint(i)] = weight 650 } 651 652 tb, err := blueprints.SetExecutionEffortWeightsTransaction(service, uintWeights) 653 if err != nil { 654 panic(fmt.Sprintf("failed to setup execution effort weights %s", err.Error())) 655 } 656 657 txError, err := b.invokeMetaTransaction( 658 b.ctx, 659 Transaction( 660 tb, 661 0), 662 ) 663 panicOnMetaInvokeErrf("failed to setup execution effort weights: %s", txError, err) 664 } 665 666 func (b *bootstrapExecutor) setupExecutionMemoryWeights(service flow.Address) { 667 weights := b.executionMemoryWeights 668 669 uintWeights := make(map[uint]uint64, len(weights)) 670 for i, weight := range weights { 671 uintWeights[uint(i)] = weight 672 } 673 674 tb, err := blueprints.SetExecutionMemoryWeightsTransaction(service, uintWeights) 675 if err != nil { 676 panic(fmt.Sprintf("failed to setup execution memory weights %s", err.Error())) 677 } 678 679 txError, err := b.invokeMetaTransaction( 680 b.ctx, 681 Transaction( 682 tb, 683 0), 684 ) 685 panicOnMetaInvokeErrf("failed to setup execution memory weights: %s", txError, err) 686 } 687 688 func (b *bootstrapExecutor) setExecutionMemoryLimitTransaction(service flow.Address) { 689 690 tb, err := blueprints.SetExecutionMemoryLimitTransaction(service, b.executionMemoryLimit) 691 if err != nil { 692 panic(fmt.Sprintf("failed to setup execution memory limit %s", err.Error())) 693 } 694 695 txError, err := b.invokeMetaTransaction( 696 b.ctx, 697 Transaction( 698 tb, 699 0), 700 ) 701 panicOnMetaInvokeErrf("failed to setup execution memory limit: %s", txError, err) 702 } 703 704 func (b *bootstrapExecutor) setupStorageForServiceAccounts( 705 service, fungibleToken, flowToken, feeContract flow.Address, 706 ) { 707 txError, err := b.invokeMetaTransaction( 708 b.ctx, 709 Transaction( 710 blueprints.SetupStorageForServiceAccountsTransaction( 711 service, 712 fungibleToken, 713 flowToken, 714 feeContract), 715 0), 716 ) 717 panicOnMetaInvokeErrf("failed to setup storage for service accounts: %s", txError, err) 718 } 719 720 func (b *bootstrapExecutor) setStakingAllowlist(service flow.Address, allowedIDs []flow.Identifier) { 721 722 txError, err := b.invokeMetaTransaction( 723 b.ctx, 724 Transaction( 725 blueprints.SetStakingAllowlistTransaction( 726 service, 727 allowedIDs, 728 ), 729 0), 730 ) 731 panicOnMetaInvokeErrf("failed to set staking allow-list: %s", txError, err) 732 } 733 734 func (b *bootstrapExecutor) registerNodes(service, fungibleToken, flowToken flow.Address) { 735 for _, id := range b.identities { 736 737 // create a staking account for the node 738 nodeAddress := b.createAccount(b.accountKeys.NodeAccountPublicKeys) 739 740 // give a vault resource to the staking account 741 txError, err := b.invokeMetaTransaction( 742 b.ctx, 743 Transaction( 744 blueprints.SetupAccountTransaction(fungibleToken, 745 flowToken, 746 nodeAddress), 747 0, 748 ), 749 ) 750 panicOnMetaInvokeErrf("failed to setup machine account: %s", txError, err) 751 752 // fund the staking account 753 txError, err = b.invokeMetaTransaction( 754 b.ctx, 755 Transaction(blueprints.FundAccountTransaction(service, 756 fungibleToken, 757 flowToken, 758 nodeAddress), 759 0), 760 ) 761 panicOnMetaInvokeErrf("failed to fund node staking account: %s", txError, err) 762 763 // register the node 764 // for collection/consensus nodes this will also create the machine account 765 // and set it up with the QC/DKG participant resource 766 txError, err = b.invokeMetaTransaction( 767 b.ctx, 768 Transaction(blueprints.RegisterNodeTransaction(service, 769 flowToken, 770 nodeAddress, 771 id), 772 0), 773 ) 774 panicOnMetaInvokeErrf("failed to register node: %s", txError, err) 775 } 776 } 777 778 func (b *bootstrapExecutor) deployStakingProxyContract(service flow.Address) { 779 contract := contracts.FlowStakingProxy() 780 txError, err := b.invokeMetaTransaction( 781 b.ctx, 782 Transaction( 783 blueprints.DeployContractTransaction(service, contract, "StakingProxy"), 784 0, 785 ), 786 ) 787 panicOnMetaInvokeErrf("failed to deploy StakingProxy contract: %s", txError, err) 788 } 789 790 func (b *bootstrapExecutor) deployLockedTokensContract(service flow.Address, fungibleTokenAddress, 791 flowTokenAddress flow.Address) { 792 793 publicKeys, err := flow.EncodeRuntimeAccountPublicKeys(b.accountKeys.ServiceAccountPublicKeys) 794 if err != nil { 795 panic(err) 796 } 797 798 contract := contracts.FlowLockedTokens( 799 fungibleTokenAddress.Hex(), 800 flowTokenAddress.Hex(), 801 service.Hex(), 802 service.Hex(), 803 service.Hex()) 804 805 txError, err := b.invokeMetaTransaction( 806 b.ctx, 807 Transaction( 808 blueprints.DeployLockedTokensTransaction(service, contract, publicKeys), 809 0, 810 ), 811 ) 812 813 panicOnMetaInvokeErrf("failed to deploy LockedTokens contract: %s", txError, err) 814 } 815 816 func (b *bootstrapExecutor) deployStakingCollection(service flow.Address, fungibleTokenAddress, flowTokenAddress flow.Address) { 817 contract := contracts.FlowStakingCollection( 818 fungibleTokenAddress.Hex(), 819 flowTokenAddress.Hex(), 820 service.Hex(), 821 service.Hex(), 822 service.Hex(), 823 service.Hex(), 824 service.Hex(), 825 service.Hex(), 826 service.Hex()) 827 txError, err := b.invokeMetaTransaction( 828 b.ctx, 829 Transaction( 830 blueprints.DeployContractTransaction(service, contract, "FlowStakingCollection"), 831 0, 832 ), 833 ) 834 panicOnMetaInvokeErrf("failed to deploy FlowStakingCollection contract: %s", txError, err) 835 } 836 837 func (b *bootstrapExecutor) setContractDeploymentRestrictions(service flow.Address, deployment *bool) { 838 if deployment == nil { 839 return 840 } 841 842 txBody, err := blueprints.SetIsContractDeploymentRestrictedTransaction(service, *deployment) 843 if err != nil { 844 panic(err) 845 } 846 txError, err := b.invokeMetaTransaction( 847 b.ctx, 848 Transaction( 849 txBody, 850 0, 851 ), 852 ) 853 panicOnMetaInvokeErrf("failed to deploy FlowStakingCollection contract: %s", txError, err) 854 } 855 856 func panicOnMetaInvokeErrf(msg string, txError errors.CodedError, err error) { 857 if txError != nil { 858 panic(fmt.Sprintf(msg, txError.Error())) 859 } 860 if err != nil { 861 panic(fmt.Sprintf(msg, err.Error())) 862 } 863 } 864 865 func FungibleTokenAddress(chain flow.Chain) flow.Address { 866 address, _ := chain.AddressAtIndex(environment.FungibleTokenAccountIndex) 867 return address 868 } 869 870 func FlowTokenAddress(chain flow.Chain) flow.Address { 871 address, _ := chain.AddressAtIndex(environment.FlowTokenAccountIndex) 872 return address 873 } 874 875 // invokeMetaTransaction invokes a meta transaction inside the context of an 876 // outer transaction. 877 // 878 // Errors that occur in a meta transaction are propagated as a single error 879 // that can be captured by the Cadence runtime and eventually disambiguated by 880 // the parent context. 881 func (b *bootstrapExecutor) invokeMetaTransaction( 882 parentCtx Context, 883 tx *TransactionProcedure, 884 ) ( 885 errors.CodedError, 886 error, 887 ) { 888 // do not deduct fees or check storage in meta transactions 889 ctx := NewContextFromParent(parentCtx, 890 WithAccountStorageLimit(false), 891 WithTransactionFeesEnabled(false), 892 WithAuthorizationChecksEnabled(false), 893 WithSequenceNumberCheckAndIncrementEnabled(false), 894 ) 895 896 // use new derived transaction data for each meta transaction. 897 // It's not necessary to cache during bootstrapping and most transactions are contract deploys anyway. 898 prog, err := derived.NewEmptyDerivedBlockData(). 899 NewDerivedTransactionData(0, 0) 900 901 if err != nil { 902 return nil, err 903 } 904 905 err = Run(tx.NewExecutor(ctx, b.txnState, prog)) 906 txErr, fatalErr := errors.SplitErrorTypes(err) 907 908 return txErr, fatalErr 909 }