diff --git a/nimbus/db/state_db.nim b/nimbus/db/state_db.nim index bb9ded52e..e0abf3843 100644 --- a/nimbus/db/state_db.nim +++ b/nimbus/db/state_db.nim @@ -135,6 +135,10 @@ proc getCode*(db: AccountStateDB, address: EthAddress): ByteRange = let codeHash = db.getCodeHash(address) result = db.trie.get(codeHash.toByteRange_Unnecessary) +proc hasCodeOrNonce*(account: AccountStateDB, address: EthAddress): bool {.inline.} = + account.getNonce(address) != 0 or account.getCodeHash(address) != EMPTY_SHA3 + proc dumpAccount*(db: AccountStateDB, addressS: string): string = let address = addressS.parseAddress return fmt"{addressS}: Storage: {db.getStorage(address, 0.u256)}; getAccount: {db.getAccount address}" + diff --git a/nimbus/utils/addresses.nim b/nimbus/utils/addresses.nim new file mode 100644 index 000000000..850952ca8 --- /dev/null +++ b/nimbus/utils/addresses.nim @@ -0,0 +1,4 @@ +import nimcrypto, eth_common, rlp + +func generateAddress*(address: EthAddress, nonce: AccountNonce): EthAddress = + result[0..19] = keccak256.digest(rlp.encodeList(address, nonce).toOpenArray).data.toOpenArray(12, 31) diff --git a/nimbus/vm/interpreter/opcodes_impl.nim b/nimbus/vm/interpreter/opcodes_impl.nim index dace995f4..2fb641f61 100644 --- a/nimbus/vm/interpreter/opcodes_impl.nim +++ b/nimbus/vm/interpreter/opcodes_impl.nim @@ -12,7 +12,7 @@ import ./gas_meter, ./gas_costs, ./opcode_values, ./vm_forks, ../memory, ../message, ../stack, ../code_stream, ../computation, ../../vm_state, ../../errors, ../../constants, ../../vm_types, - ../../db/[db_chain, state_db] + ../../db/[db_chain, state_db], ../../utils/addresses # ################################## # Syntactic sugar @@ -545,19 +545,23 @@ op create, inline = false, value, startPosition, size: let callData = computation.memory.read(memPos, len) ## TODO dynamic gas that depends on remaining gas + var + contractAddress: EthAddress + isCollision: bool - ##### getNonce type error: expression 'db' is of type: proc (vmState: untyped, readOnly: untyped, handler: untyped): untyped{.noSideEffect, gcsafe, locks: .} - # computation.vmState.db(readOnly=true): - # let creationNonce = db.getNonce(computation.msg.storageAddress) - # db.incrementNonce(computation.msg.storageAddress) - let contractAddress = ZERO_ADDRESS # generateContractAddress(computation.msg.storageAddress, creationNonce) - - let isCollision = false # TODO: db.accountHasCodeOrNonce ... + computation.vmState.mutateStateDB: + # Regarding collisions, see: https://github.com/status-im/nimbus/issues/133 + # See: https://github.com/ethereum/EIPs/issues/684 + let creationNonce = db.getNonce(computation.msg.storageAddress) + db.setNonce(computation.msg.storageAddress, creationNonce + 1) + + contractAddress = generateAddress(computation.msg.storageAddress, creationNonce) + isCollision = db.hasCodeOrNonce(contractAddress) if isCollision: debug("Address collision while creating contract", address = contractAddress.toHex) push: 0 - return + raise newException(ValidationError, "Contract creation failed, address already in use") let childMsg = prepareChildMessage( computation,