github.com/onflow/flow-go@v0.33.17/fvm/environment/account_creator.go (about)

     1  package environment
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/cadence/runtime/common"
     7  
     8  	"github.com/onflow/flow-go/fvm/errors"
     9  	"github.com/onflow/flow-go/fvm/storage/state"
    10  	"github.com/onflow/flow-go/fvm/tracing"
    11  	"github.com/onflow/flow-go/model/flow"
    12  	"github.com/onflow/flow-go/module/trace"
    13  )
    14  
    15  type AddressGenerator interface {
    16  	Bytes() []byte
    17  	NextAddress() (flow.Address, error)
    18  	CurrentAddress() flow.Address
    19  	AddressCount() uint64
    20  }
    21  
    22  type BootstrapAccountCreator interface {
    23  	CreateBootstrapAccount(
    24  		publicKeys []flow.AccountPublicKey,
    25  	) (
    26  		flow.Address,
    27  		error,
    28  	)
    29  }
    30  
    31  // This ensures cadence can't access unexpected operations while parsing
    32  // programs.
    33  type ParseRestrictedAccountCreator struct {
    34  	txnState state.NestedTransactionPreparer
    35  	impl     AccountCreator
    36  }
    37  
    38  func NewParseRestrictedAccountCreator(
    39  	txnState state.NestedTransactionPreparer,
    40  	creator AccountCreator,
    41  ) AccountCreator {
    42  	return ParseRestrictedAccountCreator{
    43  		txnState: txnState,
    44  		impl:     creator,
    45  	}
    46  }
    47  
    48  func (creator ParseRestrictedAccountCreator) CreateAccount(
    49  	runtimePayer common.Address,
    50  ) (
    51  	common.Address,
    52  	error,
    53  ) {
    54  	return parseRestrict1Arg1Ret(
    55  		creator.txnState,
    56  		trace.FVMEnvCreateAccount,
    57  		creator.impl.CreateAccount,
    58  		runtimePayer)
    59  }
    60  
    61  type AccountCreator interface {
    62  	CreateAccount(runtimePayer common.Address) (common.Address, error)
    63  }
    64  
    65  type NoAccountCreator struct {
    66  }
    67  
    68  func (NoAccountCreator) CreateAccount(
    69  	runtimePayer common.Address,
    70  ) (
    71  	common.Address,
    72  	error,
    73  ) {
    74  	return common.Address{}, errors.NewOperationNotSupportedError(
    75  		"CreateAccount")
    76  }
    77  
    78  // accountCreator make use of the storage state and the chain's address
    79  // generator to create accounts.
    80  //
    81  // It also serves as a decorator for the chain's address generator which
    82  // updates the state when next address is called (This secondary functionality
    83  // is only used in utility command line).
    84  type accountCreator struct {
    85  	txnState state.NestedTransactionPreparer
    86  	chain    flow.Chain
    87  	accounts Accounts
    88  
    89  	isServiceAccountEnabled bool
    90  
    91  	tracer  tracing.TracerSpan
    92  	meter   Meter
    93  	metrics MetricsReporter
    94  
    95  	systemContracts *SystemContracts
    96  }
    97  
    98  func NewAddressGenerator(
    99  	txnState state.NestedTransactionPreparer,
   100  	chain flow.Chain,
   101  ) AddressGenerator {
   102  	return &accountCreator{
   103  		txnState: txnState,
   104  		chain:    chain,
   105  	}
   106  }
   107  
   108  func NewBootstrapAccountCreator(
   109  	txnState state.NestedTransactionPreparer,
   110  	chain flow.Chain,
   111  	accounts Accounts,
   112  ) BootstrapAccountCreator {
   113  	return &accountCreator{
   114  		txnState: txnState,
   115  		chain:    chain,
   116  		accounts: accounts,
   117  	}
   118  }
   119  
   120  func NewAccountCreator(
   121  	txnState state.NestedTransactionPreparer,
   122  	chain flow.Chain,
   123  	accounts Accounts,
   124  	isServiceAccountEnabled bool,
   125  	tracer tracing.TracerSpan,
   126  	meter Meter,
   127  	metrics MetricsReporter,
   128  	systemContracts *SystemContracts,
   129  ) AccountCreator {
   130  	return &accountCreator{
   131  		txnState:                txnState,
   132  		chain:                   chain,
   133  		accounts:                accounts,
   134  		isServiceAccountEnabled: isServiceAccountEnabled,
   135  		tracer:                  tracer,
   136  		meter:                   meter,
   137  		metrics:                 metrics,
   138  		systemContracts:         systemContracts,
   139  	}
   140  }
   141  
   142  func (creator *accountCreator) bytes() ([]byte, error) {
   143  	stateBytes, err := creator.txnState.Get(flow.AddressStateRegisterID)
   144  	if err != nil {
   145  		return nil, fmt.Errorf(
   146  			"failed to read address generator state from the state: %w",
   147  			err)
   148  	}
   149  	return stateBytes, nil
   150  }
   151  
   152  // TODO return error instead of a panic
   153  // this requires changes outside of fvm since the type is defined on flow model
   154  // and emulator and others might be dependent on that
   155  func (creator *accountCreator) Bytes() []byte {
   156  	stateBytes, err := creator.bytes()
   157  	if err != nil {
   158  		panic(err)
   159  	}
   160  	return stateBytes
   161  }
   162  
   163  func (creator *accountCreator) constructAddressGen() (
   164  	flow.AddressGenerator,
   165  	error,
   166  ) {
   167  	stateBytes, err := creator.bytes()
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  	return creator.chain.BytesToAddressGenerator(stateBytes), nil
   172  }
   173  
   174  func (creator *accountCreator) NextAddress() (flow.Address, error) {
   175  	var address flow.Address
   176  	addressGenerator, err := creator.constructAddressGen()
   177  	if err != nil {
   178  		return address, err
   179  	}
   180  
   181  	address, err = addressGenerator.NextAddress()
   182  	if err != nil {
   183  		return address, err
   184  	}
   185  
   186  	// update the ledger state
   187  	err = creator.txnState.Set(
   188  		flow.AddressStateRegisterID,
   189  		addressGenerator.Bytes())
   190  	if err != nil {
   191  		return address, fmt.Errorf(
   192  			"failed to update the state with address generator state: %w",
   193  			err)
   194  	}
   195  	return address, nil
   196  }
   197  
   198  func (creator *accountCreator) CurrentAddress() flow.Address {
   199  	var address flow.Address
   200  	addressGenerator, err := creator.constructAddressGen()
   201  	if err != nil {
   202  		// TODO update CurrentAddress to return an error if needed
   203  		panic(err)
   204  	}
   205  
   206  	address = addressGenerator.CurrentAddress()
   207  	return address
   208  }
   209  
   210  func (creator *accountCreator) AddressCount() uint64 {
   211  	addressGenerator, err := creator.constructAddressGen()
   212  	if err != nil {
   213  		// TODO update CurrentAddress to return an error if needed
   214  		panic(err)
   215  	}
   216  
   217  	return addressGenerator.AddressCount()
   218  }
   219  
   220  func (creator *accountCreator) createBasicAccount(
   221  	publicKeys []flow.AccountPublicKey,
   222  ) (
   223  	flow.Address,
   224  	error,
   225  ) {
   226  	flowAddress, err := creator.NextAddress()
   227  	if err != nil {
   228  		return flow.EmptyAddress, err
   229  	}
   230  
   231  	err = creator.accounts.Create(publicKeys, flowAddress)
   232  	if err != nil {
   233  		return flow.EmptyAddress, fmt.Errorf("create account failed: %w", err)
   234  	}
   235  
   236  	return flowAddress, nil
   237  }
   238  
   239  func (creator *accountCreator) CreateBootstrapAccount(
   240  	publicKeys []flow.AccountPublicKey,
   241  ) (
   242  	flow.Address,
   243  	error,
   244  ) {
   245  	return creator.createBasicAccount(publicKeys)
   246  }
   247  
   248  func (creator *accountCreator) CreateAccount(
   249  	runtimePayer common.Address,
   250  ) (
   251  	common.Address,
   252  	error,
   253  ) {
   254  	defer creator.tracer.StartChildSpan(trace.FVMEnvCreateAccount).End()
   255  
   256  	err := creator.meter.MeterComputation(ComputationKindCreateAccount, 1)
   257  	if err != nil {
   258  		return common.Address{}, err
   259  	}
   260  
   261  	// don't enforce limit during account creation
   262  	var address flow.Address
   263  	creator.txnState.RunWithAllLimitsDisabled(func() {
   264  		address, err = creator.createAccount(flow.ConvertAddress(runtimePayer))
   265  	})
   266  
   267  	return common.MustBytesToAddress(address.Bytes()), err
   268  }
   269  
   270  func (creator *accountCreator) createAccount(
   271  	payer flow.Address,
   272  ) (
   273  	flow.Address,
   274  	error,
   275  ) {
   276  	address, err := creator.createBasicAccount(nil)
   277  	if err != nil {
   278  		return flow.EmptyAddress, err
   279  	}
   280  
   281  	if creator.isServiceAccountEnabled {
   282  		_, invokeErr := creator.systemContracts.SetupNewAccount(
   283  			address,
   284  			payer)
   285  		if invokeErr != nil {
   286  			return flow.EmptyAddress, invokeErr
   287  		}
   288  	}
   289  
   290  	creator.metrics.RuntimeSetNumberOfAccounts(creator.AddressCount())
   291  	return address, nil
   292  }