github.com/koko1123/flow-go-1@v0.29.6/fvm/environment/account_creator.go (about)

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