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 }