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  }