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  }