github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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 "github.com/onflow/flow-core-contracts/lib/go/templates" 10 11 "github.com/onflow/flow-go/fvm/blueprints" 12 "github.com/onflow/flow-go/fvm/environment" 13 "github.com/onflow/flow-go/fvm/errors" 14 "github.com/onflow/flow-go/fvm/evm/stdlib" 15 "github.com/onflow/flow-go/fvm/meter" 16 "github.com/onflow/flow-go/fvm/storage" 17 "github.com/onflow/flow-go/fvm/storage/logical" 18 "github.com/onflow/flow-go/fvm/systemcontracts" 19 "github.com/onflow/flow-go/model/flow" 20 "github.com/onflow/flow-go/module/epochs" 21 ) 22 23 var ( 24 DefaultAccountCreationFee = mustParseUFix64( 25 "account creation fee", 26 "0.00100000") 27 28 DefaultMinimumStorageReservation = mustParseUFix64( 29 "minimum storage reservation", 30 "0.00100000") 31 32 DefaultStorageMBPerFLOW = mustParseUFix64( 33 "storage mb per flow", 34 "100.00000000") 35 36 // DefaultTransactionFees are the default transaction fee parameters if 37 // transaction fees are on. Surge factor is 1.0, inclusion effort cost is 38 // 0.0001 (because the static inclusion effort is 1.0) and execution effort 39 // cost is 0.0 because dynamic execution fees are off. If they are off 40 // (which is the default behaviour) that means the transaction fees are 0.0. 41 DefaultTransactionFees = BootstrapProcedureFeeParameters{ 42 SurgeFactor: mustParseUFix64("fee surge factor", "1.0"), 43 InclusionEffortCost: mustParseUFix64( 44 "fee inclusion effort cost", 45 "0.00001"), 46 ExecutionEffortCost: mustParseUFix64( 47 "fee execution effort cost", 48 "0.0"), 49 } 50 51 // DefaultVersionFreezePeriod is the default NodeVersionBeacon freeze period - 52 // the number of blocks in the future where the version changes are frozen. 53 DefaultVersionFreezePeriod = cadence.UInt64(1000) 54 ) 55 56 func mustParseUFix64(name string, valueString string) cadence.UFix64 { 57 value, err := cadence.NewUFix64(valueString) 58 if err != nil { 59 panic(fmt.Errorf("invalid default %s: %w", name, err)) 60 } 61 return value 62 } 63 64 // A BootstrapProcedure is an invokable that can be used to bootstrap the ledger state 65 // with the default accounts and contracts required by the Flow virtual machine. 66 type BootstrapProcedure struct { 67 BootstrapParams 68 } 69 70 type BootstrapParams struct { 71 rootBlock *flow.Header 72 73 // genesis parameters 74 accountKeys BootstrapAccountKeys 75 initialTokenSupply cadence.UFix64 76 77 accountCreationFee cadence.UFix64 78 minimumStorageReservation cadence.UFix64 79 storagePerFlow cadence.UFix64 80 restrictedAccountCreationEnabled cadence.Bool 81 setupEVMEnabled cadence.Bool 82 83 // versionFreezePeriod is the number of blocks in the future where the version 84 // changes are frozen. The Node version beacon manages the freeze period, 85 // but this is the value used when first deploying the contract, during the 86 // bootstrap procedure. 87 versionFreezePeriod cadence.UInt64 88 89 // TODO: restrictedContractDeployment should be a bool after RestrictedDeploymentEnabled is removed from the context 90 // restrictedContractDeployment of nil means that the contract deployment is taken from the fvm Context instead of from the state. 91 // This can be used to mimic behaviour on chain before the restrictedContractDeployment is set with a service account transaction. 92 restrictedContractDeployment *bool 93 94 transactionFees BootstrapProcedureFeeParameters 95 executionEffortWeights meter.ExecutionEffortWeights 96 executionMemoryWeights meter.ExecutionMemoryWeights 97 // executionMemoryLimit of 0 means that it won't be set in the state. The FVM will use the default value from the context. 98 executionMemoryLimit uint64 99 100 // config values for epoch smart-contracts 101 epochConfig epochs.EpochConfig 102 103 // list of initial network participants for whom we will create/stake flow 104 // accounts and retrieve epoch-related resources 105 identities flow.IdentityList 106 } 107 108 type BootstrapAccountKeys struct { 109 ServiceAccountPublicKeys []flow.AccountPublicKey 110 FungibleTokenAccountPublicKeys []flow.AccountPublicKey 111 FlowTokenAccountPublicKeys []flow.AccountPublicKey 112 FlowFeesAccountPublicKeys []flow.AccountPublicKey 113 NodeAccountPublicKeys []flow.AccountPublicKey 114 } 115 116 type BootstrapProcedureFeeParameters struct { 117 SurgeFactor cadence.UFix64 118 InclusionEffortCost cadence.UFix64 119 ExecutionEffortCost cadence.UFix64 120 } 121 122 type BootstrapProcedureOption func(*BootstrapProcedure) *BootstrapProcedure 123 124 func WithInitialTokenSupply(supply cadence.UFix64) BootstrapProcedureOption { 125 return func(bp *BootstrapProcedure) *BootstrapProcedure { 126 bp.initialTokenSupply = supply 127 return bp 128 } 129 } 130 131 // WithBootstrapAccountKeys sets the public keys of the accounts that will be created during bootstrapping 132 // by default all accounts are created with the ServiceAccountPublicKey specified when calling `Bootstrap`. 133 func WithBootstrapAccountKeys(keys BootstrapAccountKeys) BootstrapProcedureOption { 134 return func(bp *BootstrapProcedure) *BootstrapProcedure { 135 bp.accountKeys = keys 136 return bp 137 } 138 } 139 140 func WithAccountCreationFee(fee cadence.UFix64) BootstrapProcedureOption { 141 return func(bp *BootstrapProcedure) *BootstrapProcedure { 142 bp.accountCreationFee = fee 143 return bp 144 } 145 } 146 147 func WithTransactionFee(fees BootstrapProcedureFeeParameters) BootstrapProcedureOption { 148 return func(bp *BootstrapProcedure) *BootstrapProcedure { 149 bp.transactionFees = fees 150 return bp 151 } 152 } 153 154 func WithExecutionEffortWeights(weights meter.ExecutionEffortWeights) BootstrapProcedureOption { 155 return func(bp *BootstrapProcedure) *BootstrapProcedure { 156 bp.executionEffortWeights = weights 157 return bp 158 } 159 } 160 161 func WithExecutionMemoryWeights(weights meter.ExecutionMemoryWeights) BootstrapProcedureOption { 162 return func(bp *BootstrapProcedure) *BootstrapProcedure { 163 bp.executionMemoryWeights = weights 164 return bp 165 } 166 } 167 168 func WithExecutionMemoryLimit(limit uint64) BootstrapProcedureOption { 169 return func(bp *BootstrapProcedure) *BootstrapProcedure { 170 bp.executionMemoryLimit = limit 171 return bp 172 } 173 } 174 175 func WithMinimumStorageReservation(reservation cadence.UFix64) BootstrapProcedureOption { 176 return func(bp *BootstrapProcedure) *BootstrapProcedure { 177 bp.minimumStorageReservation = reservation 178 return bp 179 } 180 } 181 182 func WithEpochConfig(epochConfig epochs.EpochConfig) BootstrapProcedureOption { 183 return func(bp *BootstrapProcedure) *BootstrapProcedure { 184 bp.epochConfig = epochConfig 185 return bp 186 } 187 } 188 189 func WithRootBlock(rootBlock *flow.Header) BootstrapProcedureOption { 190 return func(bp *BootstrapProcedure) *BootstrapProcedure { 191 bp.rootBlock = rootBlock 192 return bp 193 } 194 } 195 196 func WithIdentities(identities flow.IdentityList) BootstrapProcedureOption { 197 return func(bp *BootstrapProcedure) *BootstrapProcedure { 198 bp.identities = identities 199 return bp 200 } 201 } 202 203 func WithStorageMBPerFLOW(ratio cadence.UFix64) BootstrapProcedureOption { 204 return func(bp *BootstrapProcedure) *BootstrapProcedure { 205 bp.storagePerFlow = ratio 206 return bp 207 } 208 } 209 210 func WithRestrictedAccountCreationEnabled(enabled cadence.Bool) BootstrapProcedureOption { 211 return func(bp *BootstrapProcedure) *BootstrapProcedure { 212 bp.restrictedAccountCreationEnabled = enabled 213 return bp 214 } 215 } 216 217 func WithSetupEVMEnabled(enabled cadence.Bool) BootstrapProcedureOption { 218 return func(bp *BootstrapProcedure) *BootstrapProcedure { 219 bp.setupEVMEnabled = enabled 220 return bp 221 } 222 } 223 224 func WithRestrictedContractDeployment(restricted *bool) BootstrapProcedureOption { 225 return func(bp *BootstrapProcedure) *BootstrapProcedure { 226 bp.restrictedContractDeployment = restricted 227 return bp 228 } 229 } 230 231 // Bootstrap returns a new BootstrapProcedure instance configured with the provided 232 // genesis parameters. 233 func Bootstrap( 234 serviceAccountPublicKey flow.AccountPublicKey, 235 opts ...BootstrapProcedureOption, 236 ) *BootstrapProcedure { 237 bootstrapProcedure := &BootstrapProcedure{ 238 BootstrapParams: BootstrapParams{ 239 accountKeys: BootstrapAccountKeys{ 240 ServiceAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey}, 241 FungibleTokenAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey}, 242 FlowTokenAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey}, 243 NodeAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey}, 244 }, 245 transactionFees: BootstrapProcedureFeeParameters{0, 0, 0}, 246 epochConfig: epochs.DefaultEpochConfig(), 247 versionFreezePeriod: DefaultVersionFreezePeriod, 248 setupEVMEnabled: true, 249 }, 250 } 251 252 for _, applyOption := range opts { 253 bootstrapProcedure = applyOption(bootstrapProcedure) 254 } 255 return bootstrapProcedure 256 } 257 258 func (b *BootstrapProcedure) NewExecutor( 259 ctx Context, 260 txnState storage.TransactionPreparer, 261 ) ProcedureExecutor { 262 return newBootstrapExecutor(b.BootstrapParams, ctx, txnState) 263 } 264 265 func (proc *BootstrapProcedure) ComputationLimit(_ Context) uint64 { 266 return math.MaxUint64 267 } 268 269 func (proc *BootstrapProcedure) MemoryLimit(_ Context) uint64 { 270 return math.MaxUint64 271 } 272 273 func (proc *BootstrapProcedure) ShouldDisableMemoryAndInteractionLimits(_ Context) bool { 274 return true 275 } 276 277 func (BootstrapProcedure) Type() ProcedureType { 278 return BootstrapProcedureType 279 } 280 281 func (proc *BootstrapProcedure) ExecutionTime() logical.Time { 282 return 0 283 } 284 285 type bootstrapExecutor struct { 286 BootstrapParams 287 288 ctx Context 289 txnState storage.TransactionPreparer 290 291 accountCreator environment.BootstrapAccountCreator 292 } 293 294 func newBootstrapExecutor( 295 params BootstrapParams, 296 ctx Context, 297 txnState storage.TransactionPreparer, 298 ) *bootstrapExecutor { 299 return &bootstrapExecutor{ 300 BootstrapParams: params, 301 ctx: NewContextFromParent( 302 ctx, 303 WithContractDeploymentRestricted(false)), 304 txnState: txnState, 305 } 306 } 307 308 func (b *bootstrapExecutor) Cleanup() { 309 // Do nothing. 310 } 311 312 func (b *bootstrapExecutor) Output() ProcedureOutput { 313 return ProcedureOutput{} 314 } 315 316 func (b *bootstrapExecutor) Preprocess() error { 317 // Do nothing. 318 return nil 319 } 320 321 func (b *bootstrapExecutor) Execute() error { 322 if b.rootBlock == nil { 323 b.rootBlock = flow.Genesis(b.ctx.Chain.ChainID()).Header 324 } 325 326 // initialize the account addressing state 327 b.accountCreator = environment.NewBootstrapAccountCreator( 328 b.txnState, 329 b.ctx.Chain, 330 environment.NewAccounts(b.txnState)) 331 332 expectAccounts := func(n uint64) error { 333 ag := environment.NewAddressGenerator(b.txnState, b.ctx.Chain) 334 currentAddresses := ag.AddressCount() 335 if currentAddresses != n { 336 return fmt.Errorf("expected %d accounts, got %d", n, currentAddresses) 337 } 338 return nil 339 } 340 341 service := b.createServiceAccount() 342 343 err := expectAccounts(1) 344 if err != nil { 345 return err 346 } 347 348 env := templates.Environment{ 349 ServiceAccountAddress: service.String(), 350 } 351 352 b.deployViewResolver(service, &env) 353 b.deployBurner(service, &env) 354 355 err = expectAccounts(1) 356 if err != nil { 357 return err 358 } 359 360 fungibleToken := b.deployFungibleToken(&env) 361 362 err = expectAccounts(systemcontracts.FungibleTokenAccountIndex) 363 if err != nil { 364 return err 365 } 366 367 nonFungibleToken := b.deployNonFungibleToken(service, &env) 368 369 b.deployMetadataViews(fungibleToken, nonFungibleToken, &env) 370 b.deployFungibleTokenSwitchboard(fungibleToken, &env) 371 372 flowToken := b.deployFlowToken(service, &env) 373 err = expectAccounts(systemcontracts.FlowTokenAccountIndex) 374 if err != nil { 375 return err 376 } 377 378 b.deployStorageFees(service, &env) 379 feeContract := b.deployFlowFees(service, &env) 380 err = expectAccounts(systemcontracts.FlowFeesAccountIndex) 381 if err != nil { 382 return err 383 } 384 385 if b.initialTokenSupply > 0 { 386 b.mintInitialTokens(service, fungibleToken, flowToken, b.initialTokenSupply) 387 } 388 389 b.deployServiceAccount(service, &env) 390 391 b.setupParameters( 392 service, 393 b.accountCreationFee, 394 b.minimumStorageReservation, 395 b.storagePerFlow, 396 b.restrictedAccountCreationEnabled, 397 ) 398 399 b.setupFees( 400 service, 401 feeContract, 402 b.transactionFees.SurgeFactor, 403 b.transactionFees.InclusionEffortCost, 404 b.transactionFees.ExecutionEffortCost, 405 ) 406 407 b.setContractDeploymentRestrictions(service, b.restrictedContractDeployment) 408 409 b.setupExecutionWeights(service) 410 411 b.setupStorageForServiceAccounts(service, fungibleToken, flowToken, feeContract) 412 413 b.createMinter(service, flowToken) 414 415 b.deployDKG(service, &env) 416 417 b.deployQC(service, &env) 418 419 b.deployIDTableStaking(service, &env) 420 421 b.deployEpoch(service, &env) 422 423 b.deployVersionBeacon(service, b.versionFreezePeriod, &env) 424 425 b.deployRandomBeaconHistory(service, &env) 426 427 // deploy staking proxy contract to the service account 428 b.deployStakingProxyContract(service, &env) 429 430 // deploy locked tokens contract to the service account 431 b.deployLockedTokensContract(service, &env) 432 433 // deploy staking collection contract to the service account 434 b.deployStakingCollection(service, &env) 435 436 // sets up the EVM environment 437 b.setupEVM(service, nonFungibleToken, fungibleToken, flowToken) 438 439 err = expectAccounts(systemcontracts.EVMStorageAccountIndex) 440 if err != nil { 441 return err 442 } 443 444 b.registerNodes(service, fungibleToken, flowToken) 445 446 // set the list of nodes which are allowed to stake in this network 447 b.setStakingAllowlist(service, b.identities.NodeIDs()) 448 449 return nil 450 } 451 452 func (b *bootstrapExecutor) createAccount(publicKeys []flow.AccountPublicKey) flow.Address { 453 address, err := b.accountCreator.CreateBootstrapAccount(publicKeys) 454 if err != nil { 455 panic(fmt.Sprintf("failed to create account: %s", err)) 456 } 457 458 return address 459 } 460 461 func (b *bootstrapExecutor) createServiceAccount() flow.Address { 462 address, err := b.accountCreator.CreateBootstrapAccount( 463 b.accountKeys.ServiceAccountPublicKeys) 464 if err != nil { 465 panic(fmt.Sprintf("failed to create service account: %s", err)) 466 } 467 468 return address 469 } 470 471 func (b *bootstrapExecutor) deployFungibleToken(env *templates.Environment) flow.Address { 472 fungibleToken := b.createAccount(b.accountKeys.FungibleTokenAccountPublicKeys) 473 474 contract := contracts.FungibleToken(*env) 475 476 txError, err := b.invokeMetaTransaction( 477 b.ctx, 478 Transaction( 479 blueprints.DeployFungibleTokenContractTransaction(fungibleToken, contract), 480 0), 481 ) 482 env.FungibleTokenAddress = fungibleToken.String() 483 panicOnMetaInvokeErrf("failed to deploy fungible token contract: %s", txError, err) 484 return fungibleToken 485 } 486 487 func (b *bootstrapExecutor) deployNonFungibleToken(deployTo flow.Address, env *templates.Environment) flow.Address { 488 489 contract := contracts.NonFungibleToken(*env) 490 491 txError, err := b.invokeMetaTransaction( 492 b.ctx, 493 Transaction( 494 blueprints.DeployNonFungibleTokenContractTransaction(deployTo, contract), 495 0), 496 ) 497 env.NonFungibleTokenAddress = deployTo.String() 498 panicOnMetaInvokeErrf("failed to deploy non-fungible token contract: %s", txError, err) 499 return deployTo 500 } 501 502 func (b *bootstrapExecutor) deployViewResolver(deployTo flow.Address, env *templates.Environment) { 503 504 txError, err := b.invokeMetaTransaction( 505 b.ctx, 506 Transaction( 507 blueprints.DeployViewResolverContractTransaction(deployTo), 508 0), 509 ) 510 env.ViewResolverAddress = deployTo.String() 511 panicOnMetaInvokeErrf("failed to deploy view resolver contract: %s", txError, err) 512 } 513 514 func (b *bootstrapExecutor) deployBurner(deployTo flow.Address, env *templates.Environment) { 515 516 txError, err := b.invokeMetaTransaction( 517 b.ctx, 518 Transaction( 519 blueprints.DeployBurnerContractTransaction(deployTo), 520 0), 521 ) 522 env.BurnerAddress = deployTo.String() 523 panicOnMetaInvokeErrf("failed to deploy burner contract: %s", txError, err) 524 } 525 526 func (b *bootstrapExecutor) deployMetadataViews(fungibleToken, nonFungibleToken flow.Address, env *templates.Environment) { 527 528 mvContract := contracts.MetadataViews(*env) 529 530 txError, err := b.invokeMetaTransaction( 531 b.ctx, 532 Transaction( 533 blueprints.DeployMetadataViewsContractTransaction(nonFungibleToken, mvContract), 534 0), 535 ) 536 env.MetadataViewsAddress = nonFungibleToken.String() 537 panicOnMetaInvokeErrf("failed to deploy metadata views contract: %s", txError, err) 538 539 ftmvContract := contracts.FungibleTokenMetadataViews(*env) 540 541 txError, err = b.invokeMetaTransaction( 542 b.ctx, 543 Transaction( 544 blueprints.DeployFungibleTokenMetadataViewsContractTransaction(fungibleToken, ftmvContract), 545 0), 546 ) 547 env.FungibleTokenMetadataViewsAddress = fungibleToken.String() 548 panicOnMetaInvokeErrf("failed to deploy fungible token metadata views contract: %s", txError, err) 549 } 550 551 func (b *bootstrapExecutor) deployFungibleTokenSwitchboard(deployTo flow.Address, env *templates.Environment) { 552 553 contract := contracts.FungibleTokenSwitchboard(*env) 554 555 txError, err := b.invokeMetaTransaction( 556 b.ctx, 557 Transaction( 558 blueprints.DeployFungibleTokenSwitchboardContractTransaction(deployTo, contract), 559 0), 560 ) 561 env.FungibleTokenSwitchboardAddress = deployTo.String() 562 panicOnMetaInvokeErrf("failed to deploy fungible token switchboard contract: %s", txError, err) 563 } 564 565 func (b *bootstrapExecutor) deployFlowToken(service flow.Address, env *templates.Environment) flow.Address { 566 flowToken := b.createAccount(b.accountKeys.FlowTokenAccountPublicKeys) 567 568 contract := contracts.FlowToken(*env) 569 570 txError, err := b.invokeMetaTransaction( 571 b.ctx, 572 Transaction( 573 blueprints.DeployFlowTokenContractTransaction( 574 service, 575 flowToken, 576 contract), 577 0), 578 ) 579 env.FlowTokenAddress = flowToken.String() 580 panicOnMetaInvokeErrf("failed to deploy Flow token contract: %s", txError, err) 581 return flowToken 582 } 583 584 func (b *bootstrapExecutor) deployFlowFees(service flow.Address, env *templates.Environment) flow.Address { 585 flowFees := b.createAccount(b.accountKeys.FlowFeesAccountPublicKeys) 586 587 contract := contracts.FlowFees( 588 *env, 589 ) 590 591 txError, err := b.invokeMetaTransaction( 592 b.ctx, 593 Transaction( 594 blueprints.DeployTxFeesContractTransaction( 595 flowFees, 596 service, 597 contract, 598 ), 599 0), 600 ) 601 env.FlowFeesAddress = flowFees.String() 602 panicOnMetaInvokeErrf("failed to deploy fees contract: %s", txError, err) 603 return flowFees 604 } 605 606 func (b *bootstrapExecutor) deployStorageFees(deployTo flow.Address, env *templates.Environment) { 607 contract := contracts.FlowStorageFees(*env) 608 609 // deploy storage fees contract on the service account 610 txError, err := b.invokeMetaTransaction( 611 b.ctx, 612 Transaction( 613 blueprints.DeployStorageFeesContractTransaction( 614 deployTo, 615 contract), 616 0), 617 ) 618 env.StorageFeesAddress = deployTo.String() 619 panicOnMetaInvokeErrf("failed to deploy storage fees contract: %s", txError, err) 620 } 621 622 func (b *bootstrapExecutor) createMinter(service, flowToken flow.Address) { 623 txError, err := b.invokeMetaTransaction( 624 b.ctx, 625 Transaction( 626 blueprints.CreateFlowTokenMinterTransaction( 627 service, 628 flowToken), 629 0), 630 ) 631 panicOnMetaInvokeErrf("failed to create flow token minter: %s", txError, err) 632 } 633 634 func (b *bootstrapExecutor) deployDKG(deployTo flow.Address, env *templates.Environment) { 635 contract := contracts.FlowDKG() 636 txError, err := b.invokeMetaTransaction( 637 b.ctx, 638 Transaction( 639 blueprints.DeployContractTransaction(deployTo, contract, "FlowDKG"), 640 0, 641 ), 642 ) 643 env.DkgAddress = deployTo.String() 644 panicOnMetaInvokeErrf("failed to deploy DKG contract: %s", txError, err) 645 } 646 647 func (b *bootstrapExecutor) deployQC(deployTo flow.Address, env *templates.Environment) { 648 contract := contracts.FlowQC() 649 txError, err := b.invokeMetaTransaction( 650 b.ctx, 651 Transaction( 652 blueprints.DeployContractTransaction(deployTo, contract, "FlowClusterQC"), 653 0, 654 ), 655 ) 656 env.QuorumCertificateAddress = deployTo.String() 657 panicOnMetaInvokeErrf("failed to deploy QC contract: %s", txError, err) 658 } 659 660 func (b *bootstrapExecutor) deployIDTableStaking(deployTo flow.Address, env *templates.Environment) { 661 662 contract := contracts.FlowIDTableStaking( 663 *env, 664 ) 665 666 txError, err := b.invokeMetaTransaction( 667 b.ctx, 668 Transaction( 669 blueprints.DeployIDTableStakingTransaction(deployTo, 670 contract, 671 b.epochConfig.EpochTokenPayout, 672 b.epochConfig.RewardCut), 673 0, 674 ), 675 ) 676 env.IDTableAddress = deployTo.String() 677 panicOnMetaInvokeErrf("failed to deploy IDTableStaking contract: %s", txError, err) 678 } 679 680 func (b *bootstrapExecutor) deployEpoch(deployTo flow.Address, env *templates.Environment) { 681 682 contract := contracts.FlowEpoch(*env) 683 684 context := NewContextFromParent(b.ctx, 685 WithBlockHeader(b.rootBlock), 686 WithBlocks(&environment.NoopBlockFinder{}), 687 ) 688 689 txError, err := b.invokeMetaTransaction( 690 context, 691 Transaction( 692 blueprints.DeployEpochTransaction(deployTo, contract, b.epochConfig), 693 0, 694 ), 695 ) 696 env.EpochAddress = deployTo.String() 697 panicOnMetaInvokeErrf("failed to deploy Epoch contract: %s", txError, err) 698 } 699 700 func (b *bootstrapExecutor) deployServiceAccount(deployTo flow.Address, env *templates.Environment) { 701 contract := contracts.FlowServiceAccount( 702 *env, 703 ) 704 705 txError, err := b.invokeMetaTransaction( 706 b.ctx, 707 Transaction( 708 blueprints.DeployContractTransaction( 709 deployTo, 710 contract, 711 "FlowServiceAccount"), 712 0), 713 ) 714 panicOnMetaInvokeErrf("failed to deploy service account contract: %s", txError, err) 715 } 716 717 func (b *bootstrapExecutor) mintInitialTokens( 718 service, fungibleToken, flowToken flow.Address, 719 initialSupply cadence.UFix64, 720 ) { 721 txError, err := b.invokeMetaTransaction( 722 b.ctx, 723 Transaction( 724 blueprints.MintFlowTokenTransaction( 725 fungibleToken, 726 flowToken, 727 service, 728 initialSupply), 729 0), 730 ) 731 panicOnMetaInvokeErrf("failed to mint initial token supply: %s", txError, err) 732 } 733 734 func (b *bootstrapExecutor) setupParameters( 735 service flow.Address, 736 addressCreationFee, 737 minimumStorageReservation, 738 storagePerFlow cadence.UFix64, 739 restrictedAccountCreationEnabled cadence.Bool, 740 ) { 741 txError, err := b.invokeMetaTransaction( 742 b.ctx, 743 Transaction( 744 blueprints.SetupParametersTransaction( 745 service, 746 addressCreationFee, 747 minimumStorageReservation, 748 storagePerFlow, 749 restrictedAccountCreationEnabled, 750 ), 751 0), 752 ) 753 panicOnMetaInvokeErrf("failed to setup parameters: %s", txError, err) 754 } 755 756 func (b *bootstrapExecutor) setupFees( 757 service, flowFees flow.Address, 758 surgeFactor, inclusionEffortCost, executionEffortCost cadence.UFix64, 759 ) { 760 txError, err := b.invokeMetaTransaction( 761 b.ctx, 762 Transaction( 763 blueprints.SetupFeesTransaction( 764 service, 765 flowFees, 766 surgeFactor, 767 inclusionEffortCost, 768 executionEffortCost, 769 ), 770 0), 771 ) 772 panicOnMetaInvokeErrf("failed to setup fees: %s", txError, err) 773 } 774 775 func (b *bootstrapExecutor) setupExecutionWeights(service flow.Address) { 776 // if executionEffortWeights were not set skip this part and just use the defaults. 777 if b.executionEffortWeights != nil { 778 b.setupExecutionEffortWeights(service) 779 } 780 // if executionMemoryWeights were not set skip this part and just use the defaults. 781 if b.executionMemoryWeights != nil { 782 b.setupExecutionMemoryWeights(service) 783 } 784 if b.executionMemoryLimit != 0 { 785 b.setExecutionMemoryLimitTransaction(service) 786 } 787 } 788 789 func (b *bootstrapExecutor) setupExecutionEffortWeights(service flow.Address) { 790 weights := b.executionEffortWeights 791 792 uintWeights := make(map[uint]uint64, len(weights)) 793 for i, weight := range weights { 794 uintWeights[uint(i)] = weight 795 } 796 797 tb, err := blueprints.SetExecutionEffortWeightsTransaction(service, uintWeights) 798 if err != nil { 799 panic(fmt.Sprintf("failed to setup execution effort weights %s", err.Error())) 800 } 801 802 txError, err := b.invokeMetaTransaction( 803 b.ctx, 804 Transaction( 805 tb, 806 0), 807 ) 808 panicOnMetaInvokeErrf("failed to setup execution effort weights: %s", txError, err) 809 } 810 811 func (b *bootstrapExecutor) setupExecutionMemoryWeights(service flow.Address) { 812 weights := b.executionMemoryWeights 813 814 uintWeights := make(map[uint]uint64, len(weights)) 815 for i, weight := range weights { 816 uintWeights[uint(i)] = weight 817 } 818 819 tb, err := blueprints.SetExecutionMemoryWeightsTransaction(service, uintWeights) 820 if err != nil { 821 panic(fmt.Sprintf("failed to setup execution memory weights %s", err.Error())) 822 } 823 824 txError, err := b.invokeMetaTransaction( 825 b.ctx, 826 Transaction( 827 tb, 828 0), 829 ) 830 panicOnMetaInvokeErrf("failed to setup execution memory weights: %s", txError, err) 831 } 832 833 func (b *bootstrapExecutor) setExecutionMemoryLimitTransaction(service flow.Address) { 834 835 tb, err := blueprints.SetExecutionMemoryLimitTransaction(service, b.executionMemoryLimit) 836 if err != nil { 837 panic(fmt.Sprintf("failed to setup execution memory limit %s", err.Error())) 838 } 839 840 txError, err := b.invokeMetaTransaction( 841 b.ctx, 842 Transaction( 843 tb, 844 0), 845 ) 846 panicOnMetaInvokeErrf("failed to setup execution memory limit: %s", txError, err) 847 } 848 849 func (b *bootstrapExecutor) setupStorageForServiceAccounts( 850 service, fungibleToken, flowToken, feeContract flow.Address, 851 ) { 852 txError, err := b.invokeMetaTransaction( 853 b.ctx, 854 Transaction( 855 blueprints.SetupStorageForServiceAccountsTransaction( 856 service, 857 fungibleToken, 858 flowToken, 859 feeContract), 860 0), 861 ) 862 panicOnMetaInvokeErrf("failed to setup storage for service accounts: %s", txError, err) 863 } 864 865 func (b *bootstrapExecutor) setupStorageForAccount( 866 account, service, fungibleToken, flowToken flow.Address, 867 ) { 868 txError, err := b.invokeMetaTransaction( 869 b.ctx, 870 Transaction( 871 blueprints.SetupStorageForAccountTransaction( 872 account, 873 service, 874 fungibleToken, 875 flowToken), 876 0), 877 ) 878 panicOnMetaInvokeErrf("failed to setup storage for service accounts: %s", txError, err) 879 } 880 881 func (b *bootstrapExecutor) setStakingAllowlist( 882 service flow.Address, 883 allowedIDs []flow.Identifier, 884 ) { 885 886 txError, err := b.invokeMetaTransaction( 887 b.ctx, 888 Transaction( 889 blueprints.SetStakingAllowlistTransaction( 890 service, 891 allowedIDs, 892 ), 893 0), 894 ) 895 panicOnMetaInvokeErrf("failed to set staking allow-list: %s", txError, err) 896 } 897 898 func (b *bootstrapExecutor) setupEVM(serviceAddress, nonFungibleTokenAddress, fungibleTokenAddress, flowTokenAddress flow.Address) { 899 if b.setupEVMEnabled { 900 // account for storage 901 // we dont need to deploy anything to this account, but it needs to exist 902 // so that we can store the EVM state on it 903 evmAcc := b.createAccount(nil) 904 b.setupStorageForAccount(evmAcc, serviceAddress, fungibleTokenAddress, flowTokenAddress) 905 906 // deploy the EVM contract to the service account 907 tx := blueprints.DeployContractTransaction( 908 serviceAddress, 909 stdlib.ContractCode(nonFungibleTokenAddress, fungibleTokenAddress, flowTokenAddress), 910 stdlib.ContractName, 911 ) 912 // WithEVMEnabled should only be used after we create an account for storage 913 txError, err := b.invokeMetaTransaction( 914 NewContextFromParent(b.ctx, WithEVMEnabled(true)), 915 Transaction(tx, 0), 916 ) 917 panicOnMetaInvokeErrf("failed to deploy EVM contract: %s", txError, err) 918 } 919 } 920 921 func (b *bootstrapExecutor) registerNodes(service, fungibleToken, flowToken flow.Address) { 922 for _, id := range b.identities { 923 924 // create a staking account for the node 925 nodeAddress := b.createAccount(b.accountKeys.NodeAccountPublicKeys) 926 927 // give a vault resource to the staking account 928 txError, err := b.invokeMetaTransaction( 929 b.ctx, 930 Transaction( 931 blueprints.SetupAccountTransaction(fungibleToken, 932 flowToken, 933 nodeAddress), 934 0, 935 ), 936 ) 937 panicOnMetaInvokeErrf("failed to setup machine account: %s", txError, err) 938 939 // fund the staking account 940 txError, err = b.invokeMetaTransaction( 941 b.ctx, 942 Transaction(blueprints.FundAccountTransaction( 943 service, 944 fungibleToken, 945 flowToken, 946 nodeAddress), 947 0), 948 ) 949 panicOnMetaInvokeErrf("failed to fund node staking account: %s", txError, err) 950 951 // register the node 952 // for collection/consensus nodes this will also create the machine account 953 // and set it up with the QC/DKG participant resource 954 txError, err = b.invokeMetaTransaction( 955 b.ctx, 956 Transaction(blueprints.RegisterNodeTransaction( 957 service, 958 flowToken, 959 fungibleToken, 960 nodeAddress, 961 id), 962 0), 963 ) 964 panicOnMetaInvokeErrf("failed to register node: %s", txError, err) 965 } 966 } 967 968 func (b *bootstrapExecutor) deployStakingProxyContract(deployTo flow.Address, env *templates.Environment) { 969 contract := contracts.FlowStakingProxy() 970 txError, err := b.invokeMetaTransaction( 971 b.ctx, 972 Transaction( 973 blueprints.DeployContractTransaction(deployTo, contract, "StakingProxy"), 974 0, 975 ), 976 ) 977 env.StakingProxyAddress = deployTo.String() 978 panicOnMetaInvokeErrf("failed to deploy StakingProxy contract: %s", txError, err) 979 } 980 981 func (b *bootstrapExecutor) deployVersionBeacon( 982 deployTo flow.Address, 983 versionFreezePeriod cadence.UInt64, 984 env *templates.Environment, 985 ) { 986 tx := blueprints.DeployNodeVersionBeaconTransaction(deployTo, versionFreezePeriod) 987 txError, err := b.invokeMetaTransaction( 988 b.ctx, 989 Transaction( 990 tx, 991 0, 992 ), 993 ) 994 env.NodeVersionBeaconAddress = deployTo.String() 995 panicOnMetaInvokeErrf("failed to deploy NodeVersionBeacon contract: %s", txError, err) 996 } 997 998 func (b *bootstrapExecutor) deployRandomBeaconHistory( 999 deployTo flow.Address, 1000 env *templates.Environment, 1001 ) { 1002 tx := blueprints.DeployRandomBeaconHistoryTransaction(deployTo) 1003 txError, err := b.invokeMetaTransaction( 1004 b.ctx, 1005 Transaction( 1006 tx, 1007 0, 1008 ), 1009 ) 1010 env.RandomBeaconHistoryAddress = deployTo.String() 1011 panicOnMetaInvokeErrf("failed to deploy RandomBeaconHistory history contract: %s", txError, err) 1012 } 1013 1014 func (b *bootstrapExecutor) deployLockedTokensContract( 1015 deployTo flow.Address, 1016 env *templates.Environment, 1017 ) { 1018 1019 publicKeys, err := flow.EncodeRuntimeAccountPublicKeys(b.accountKeys.ServiceAccountPublicKeys) 1020 if err != nil { 1021 panic(err) 1022 } 1023 1024 contract := contracts.FlowLockedTokens(*env) 1025 1026 txError, err := b.invokeMetaTransaction( 1027 b.ctx, 1028 Transaction( 1029 blueprints.DeployLockedTokensTransaction(deployTo, contract, publicKeys), 1030 0, 1031 ), 1032 ) 1033 env.LockedTokensAddress = deployTo.String() 1034 panicOnMetaInvokeErrf("failed to deploy LockedTokens contract: %s", txError, err) 1035 } 1036 1037 func (b *bootstrapExecutor) deployStakingCollection( 1038 deployTo flow.Address, 1039 env *templates.Environment, 1040 ) { 1041 contract := contracts.FlowStakingCollection(*env) 1042 txError, err := b.invokeMetaTransaction( 1043 b.ctx, 1044 Transaction( 1045 blueprints.DeployContractTransaction(deployTo, contract, "FlowStakingCollection"), 1046 0, 1047 ), 1048 ) 1049 env.StakingCollectionAddress = deployTo.String() 1050 panicOnMetaInvokeErrf("failed to deploy FlowStakingCollection contract: %s", txError, err) 1051 } 1052 1053 func (b *bootstrapExecutor) setContractDeploymentRestrictions( 1054 service flow.Address, 1055 deployment *bool, 1056 ) { 1057 if deployment == nil { 1058 return 1059 } 1060 1061 txBody, err := blueprints.SetIsContractDeploymentRestrictedTransaction(service, *deployment) 1062 if err != nil { 1063 panic(err) 1064 } 1065 txError, err := b.invokeMetaTransaction( 1066 b.ctx, 1067 Transaction( 1068 txBody, 1069 0, 1070 ), 1071 ) 1072 panicOnMetaInvokeErrf("failed to deploy FlowStakingCollection contract: %s", txError, err) 1073 } 1074 1075 func panicOnMetaInvokeErrf(msg string, txError errors.CodedError, err error) { 1076 if txError != nil { 1077 panic(fmt.Sprintf(msg, txError.Error())) 1078 } 1079 if err != nil { 1080 panic(fmt.Sprintf(msg, err.Error())) 1081 } 1082 } 1083 1084 // invokeMetaTransaction invokes a meta transaction inside the context of an 1085 // outer transaction. 1086 // 1087 // Errors that occur in a meta transaction are propagated as a single error 1088 // that can be captured by the Cadence runtime and eventually disambiguated by 1089 // the parent context. 1090 func (b *bootstrapExecutor) invokeMetaTransaction( 1091 parentCtx Context, 1092 tx *TransactionProcedure, 1093 ) ( 1094 errors.CodedError, 1095 error, 1096 ) { 1097 // do not deduct fees or check storage in meta transactions 1098 ctx := NewContextFromParent(parentCtx, 1099 WithAccountStorageLimit(false), 1100 WithTransactionFeesEnabled(false), 1101 WithAuthorizationChecksEnabled(false), 1102 WithSequenceNumberCheckAndIncrementEnabled(false), 1103 1104 // disable interaction and computation limits for bootstrapping 1105 WithMemoryAndInteractionLimitsDisabled(), 1106 WithComputationLimit(math.MaxUint64), 1107 ) 1108 1109 executor := tx.NewExecutor(ctx, b.txnState) 1110 err := Run(executor) 1111 1112 return executor.Output().Err, err 1113 }