implement EIP1014: Create2 opcode

This commit is contained in:
andri lim 2019-05-07 10:23:27 +07:00 committed by zah
parent 480a3d2cab
commit 5f2be4231e
4 changed files with 71 additions and 41 deletions

View File

@ -20,5 +20,21 @@ func keccakHash*(value: openarray[byte]): Hash256 {.inline.} =
func generateAddress*(address: EthAddress, nonce: AccountNonce): EthAddress =
result[0..19] = keccakHash(rlp.encodeList(address, nonce)).data.toOpenArray(12, 31)
func generateSafeAddress*(address: EthAddress, salt: Uint256, data: openArray[byte]): EthAddress =
const prefix = [0xff.byte]
let dataHash = keccakHash(data)
var hashResult: Hash256
var ctx: keccak256
ctx.init()
ctx.update(prefix)
ctx.update(address)
ctx.update(salt.toByteArrayBE())
ctx.update(dataHash.data)
ctx.finish hashResult.data
ctx.clear()
result[0..19] = hashResult.data.toOpenArray(12, 31)
func hash*(b: BlockHeader): Hash256 {.inline.} =
rlpHash(b)

View File

@ -196,7 +196,7 @@ proc applyMessage*(computation: BaseComputation, opCode: static[Op]) =
computation.dispose()
# EIP161 nonce incrementation
when opCode == Create:
when opCode in {Create, Create2}:
if computation.getFork >= FkSpurious:
computation.vmState.mutateStateDb:
db.incNonce(computation.msg.storageAddress)

View File

@ -353,6 +353,10 @@ template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) =
if gasParams.sd_condition:
result.gasCost += static(FeeSchedule[GasNewAccount])
func `prefix gasCreate2`(currentMemSize, memOffset, memLength: Natural): GasInt {.nimcall.} =
result = static(FeeSchedule[GasCreate]) +
static(FeeSchedule[GasSha3Word]) * (memLength).wordCount
# ###################################################################################################
# TODO - change this `let` into `const` - pending: https://github.com/nim-lang/Nim/issues/8015
@ -532,7 +536,7 @@ template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) =
CallCode: complex `prefix gasCall`,
Return: memExpansion `prefix gasHalt`,
DelegateCall: complex `prefix gasCall`,
Create2: complex `prefix gasCall`,
Create2: memExpansion `prefix gasCreate2`,
StaticCall: complex `prefix gasCall`,
Revert: memExpansion `prefix gasHalt`,
Invalid: fixed GasZero,

View File

@ -503,14 +503,18 @@ genLog()
# ##########################################
# f0s: System operations.
proc canTransfer(computation: BaseComputation, memPos, memLen: int, value: Uint256): bool =
let gasParams = GasParams(kind: Create,
cr_currentMemSize: computation.memory.len,
cr_memOffset: memPos,
cr_memLength: memLen
)
let gasCost = computation.gasCosts[Create].c_handler(1.u256, gasParams).gasCost
let reason = &"CREATE: GasCreate + {memLen} * memory expansion"
proc canTransfer(computation: BaseComputation, memPos, memLen: int, value: Uint256, opCode: static[Op]): bool =
when opCode == Create:
let gasParams = GasParams(kind: Create,
cr_currentMemSize: computation.memory.len,
cr_memOffset: memPos,
cr_memLength: memLen
)
let gasCost = computation.gasCosts[Create].c_handler(1.u256, gasParams).gasCost
let reason = &"CREATE: GasCreate + {memLen} * memory expansion"
else:
let gasCost = computation.gasCosts[Create2].m_handler(0, 0, memLen)
let reason = &"CREATE2: GasCreate + {memLen} * GasSha3Word"
computation.gasMeter.consumeGas(gasCost, reason = reason)
computation.memory.extend(memPos, memLen)
@ -535,7 +539,7 @@ proc canTransfer(computation: BaseComputation, memPos, memLen: int, value: Uint2
result = true
proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256): BaseComputation =
proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256, opCode: static[Op]): BaseComputation =
let
callData = computation.memory.read(memPos, len)
@ -553,14 +557,20 @@ proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256)
contractAddress: EthAddress
isCollision: bool
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)
when opCode == Create:
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)
contractAddress = generateAddress(computation.msg.storageAddress, creationNonce)
isCollision = db.hasCodeOrNonce(contractAddress)
else:
computation.vmState.mutateStateDB:
let salt = computation.stack.popInt()
contractAddress = generateSafeAddress(computation.msg.storageAddress, salt, callData)
isCollision = db.hasCodeOrNonce(contractAddress)
if isCollision:
debug "Address collision while creating contract", address = contractAddress.toHex
@ -585,27 +595,31 @@ proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256)
childMsg,
some(computation.getFork))
op create, inline = false, value, startPosition, size:
## 0xf0, Create a new account with associated code.
let (memPos, len) = (startPosition.cleanMemRef, size.cleanMemRef)
if not computation.canTransfer(memPos, len, value):
push: 0
return
var childComp = setupCreate(computation, memPos, len, value)
if childComp.isNil: return
computation.child = childComp
continuation(childComp):
computation.addChildComputation(childComp)
if childComp.isError:
template genCreate(callName: untyped, opCode: Op): untyped =
op callName, inline = false, value, startPosition, size:
## 0xf0, Create a new account with associated code.
let (memPos, len) = (startPosition.cleanMemRef, size.cleanMemRef)
if not computation.canTransfer(memPos, len, value, opCode):
push: 0
else:
push: childComp.msg.storageAddress
return
checkInStaticContext(computation)
childComp.applyMessage(Create)
var childComp = setupCreate(computation, memPos, len, value, opCode)
if childComp.isNil: return
computation.child = childComp
continuation(childComp):
addChildComputation(computation, childComp)
if childComp.isError:
push: 0
else:
push: childComp.msg.storageAddress
checkInStaticContext(computation)
childComp.applyMessage(Create)
genCreate(create, Create)
genCreate(create2, Create2)
proc callParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) =
let gas = computation.stack.popInt()
@ -909,7 +923,3 @@ op extCodeHash, inline = true:
push: 0
else:
push: computation.vmState.readOnlyStateDB.getCodeHash(address)
op create2, inline = false:
# TODO: implementation
discard