Skip to content

Commit

Permalink
EIP-1014 implementation. #14
Browse files Browse the repository at this point in the history
  • Loading branch information
dcaoyuan committed Mar 31, 2019
1 parent dcf8a61 commit a082d0d
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 17 deletions.
4 changes: 4 additions & 0 deletions khipu-eth/src/main/scala/khipu/vm/EvmConfig.scala
Expand Up @@ -49,6 +49,7 @@ object EvmConfig {
eip198 = false,
eip658 = false,
eip145 = false,
eip1014 = false,
eip1052 = false,
eip1283 = false
)
Expand All @@ -68,6 +69,7 @@ object EvmConfig {
eip198 = false,
eip658 = false,
eip145 = false,
eip1014 = false,
eip1052 = false,
eip1283 = false
)
Expand Down Expand Up @@ -121,6 +123,7 @@ object EvmConfig {
val ConstantinopleConfig = ByzantiumConfig.copy(
opCodes = OpCodes.ConstantinopleCodes,
eip145 = true,
eip1014 = true,
eip1052 = true
)
}
Expand All @@ -140,6 +143,7 @@ final case class EvmConfig(
eip198: Boolean,
eip658: Boolean,
eip145: Boolean,
eip1014: Boolean,
eip1052: Boolean,
eip1283: Boolean
) {
Expand Down
76 changes: 61 additions & 15 deletions khipu-eth/src/main/scala/khipu/vm/OpCode.scala
Expand Up @@ -170,6 +170,7 @@ object OpCodes {
SHL,
SHR,
SAR,
CREATE2,
EXTCODEHASH
)
}
Expand Down Expand Up @@ -1028,31 +1029,21 @@ case object LOG2 extends LogOp(0xa2)
case object LOG3 extends LogOp(0xa3)
case object LOG4 extends LogOp(0xa4)

case object CREATE extends OpCode[(UInt256, UInt256, UInt256)](0xf0, 3, 1) {
protected def constGasFn(s: FeeSchedule) = s.G_create
protected def getParams[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S]) = {
val List(endowment, inOffset, inSize) = state.stack.pop(3)
if (inOffset.compareTo(UInt256.MaxInt) > 0 || inSize.compareTo(UInt256.MaxInt) > 0) {
state.withError(ArithmeticException)
}
(endowment, inOffset, inSize)
}
sealed abstract class CreatOp[P](code: Int, delta: Int, alpha: Int) extends OpCode[P](code.toByte, delta, alpha) {

protected def exec[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S], params: (UInt256, UInt256, UInt256)): ProgramState[W, S] = {
final protected def doExec[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S], endowment: UInt256, inOffset: UInt256, inSize: UInt256, salt: UInt256, params: P): ProgramState[W, S] = {
if (state.context.isStaticCall) {
state.withError(StaticCallModification)
} else {
val (endowment, inOffset, inSize) = params

state.resetReturnDataBuffer() // reset before call

val isValidCall = state.env.callDepth < EvmConfig.MaxCallDepth && endowment <= state.ownBalance

if (isValidCall) {

val initCode = state.memory.load(inOffset.intValueSafe, inSize.intValueSafe)
val initCode = state.memory.load(inOffset.intValueSafe, inSize.intValueSafe).toArray
// if creation fails at this point we still leave the creators nonce incremented
val (newAddress, checkpoint, worldAtCheckpoint) = state.world.createAddressByOpCode(state.env.ownerAddr) match {
val (newAddress, checkpoint, worldAtCheckpoint) = createContactAddress[W, S](state, initCode, salt.bytes) match {
case (address, world) => (address, world.copy, world)
}
//println(s"newAddress: $newAddress via ${state.env.ownerAddr} in CREATE")
Expand Down Expand Up @@ -1156,9 +1147,64 @@ case object CREATE extends OpCode[(UInt256, UInt256, UInt256)](0xf0, 3, 1) {
}
}

protected def createContactAddress[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S], initCode: Array[Byte], salt: Array[Byte]): (Address, W)
}
case object CREATE extends CreatOp[(UInt256, UInt256, UInt256)](0xf0, 3, 1) {
protected def constGasFn(s: FeeSchedule) = s.G_create
protected def getParams[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S]) = {
val List(endowment, inOffset, inSize) = state.stack.pop(3)
if (inOffset.compareTo(UInt256.MaxInt) > 0 || inSize.compareTo(UInt256.MaxInt) > 0) {
state.withError(ArithmeticException)
}
(endowment, inOffset, inSize)
}

protected def exec[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S], params: (UInt256, UInt256, UInt256)): ProgramState[W, S] = {
val (endowment, inOffset, inSize) = params
doExec(state, endowment, inOffset, inSize, null, params)
}

protected def createContactAddress[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S], initCode: Array[Byte], salt: Array[Byte]): (Address, W) = {
state.world.createAddressByOpCode(state.env.ownerAddr)
}

protected def varGas[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S], params: (UInt256, UInt256, UInt256)): Long = {
val (_, inOffset, inSize) = params
state.config.calcMemCost(state.memory.size, inOffset.longValueSafe, inSize.longValueSafe)
val memCost = state.config.calcMemCost(state.memory.size, inOffset.longValueSafe, inSize.longValueSafe)
memCost
}
}

/**
* CREATE2 is identical to CREATE, except the following line:
* val (newAddress, checkpoint, worldAtCheckpoint) = state.world.createAddressBySalt(state.env.ownerAddr, initCode, salt.bytes) match {
*
* TODO reduce redundancy code of CREATE and CREATE2
*/
case object CREATE2 extends CreatOp[(UInt256, UInt256, UInt256, UInt256)](0xf5, 4, 1) {
protected def constGasFn(s: FeeSchedule) = s.G_create
protected def getParams[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S]) = {
val List(endowment, inOffset, inSize, salt) = state.stack.pop(4)
if (inOffset.compareTo(UInt256.MaxInt) > 0 || inSize.compareTo(UInt256.MaxInt) > 0) {
state.withError(ArithmeticException)
}
(endowment, inOffset, inSize, salt)
}

protected def exec[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S], params: (UInt256, UInt256, UInt256, UInt256)): ProgramState[W, S] = {
val (endowment, inOffset, inSize, salt) = params
doExec(state, endowment, inOffset, inSize, salt, params)
}

protected def createContactAddress[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S], initCode: Array[Byte], salt: Array[Byte]): (Address, W) = {
state.world.createAddressBySalt(state.env.ownerAddr, initCode, salt)
}

protected def varGas[W <: WorldState[W, S], S <: Storage[S]](state: ProgramState[W, S], params: (UInt256, UInt256, UInt256, UInt256)): Long = {
val (_, inOffset, inSize, _) = params
val memCost = state.config.calcMemCost(state.memory.size, inOffset.longValueSafe, inSize.longValueSafe)
val shaCost = state.config.feeSchedule.G_sha3word * UInt256.wordsForBytes(inSize.longValueSafe)
memCost + shaCost
}
}

Expand Down
33 changes: 31 additions & 2 deletions khipu-eth/src/main/scala/khipu/vm/WorldState.scala
Expand Up @@ -91,8 +91,8 @@ trait WorldState[W <: WorldState[W, S], S <: Storage[S]] { self: W =>
*/
def createAddress(creatorAddr: Address): Address = {
val creatorAccount = getGuaranteedAccount(creatorAddr)
val hash = crypto.kec256(rlp.encode(RLPList(creatorAddr.bytes, rlp.toRLPEncodable(creatorAccount.nonce - UInt256.One))))
Address(hash)
val addr = crypto.kec256(rlp.encode(RLPList(creatorAddr.bytes, rlp.toRLPEncodable(creatorAccount.nonce - UInt256.One))))
Address(addr)
}

/**
Expand All @@ -107,6 +107,35 @@ trait WorldState[W <: WorldState[W, S], S <: Storage[S]] { self: W =>
(world1.createAddress(creatorAddr), world1)
}

def createAddressBySalt(creatorAddr: Address, initCode: Array[Byte], salt: Array[Byte]): (Address, W) = {
val creatorAccount = getGuaranteedAccount(creatorAddr)
val world1 = saveAccount(creatorAddr, creatorAccount.increaseNonce())
(world1.createSaltAddrress(creatorAddr.toArray, initCode, salt), world1)
}

/**
* sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code)))[12:]
*
* @param creatorAddr - creating address
* @param initCode - contract init code
* @param salt - salt to make different result addresses, 32 bytes stack item
* @return new address
*/
private def createSaltAddrress(creatorAddr: Array[Byte], initCode: Array[Byte], salt: Array[Byte]): Address = {
val data = Array.ofDim[Byte](1 + creatorAddr.length + salt.length + 32)
data(0) = 0xff.toByte
var offset = 1
System.arraycopy(creatorAddr, 0, data, offset, creatorAddr.length)
offset += creatorAddr.length
System.arraycopy(salt, 0, data, offset, salt.length)
offset += salt.length
val sha3InitCode = crypto.kec256(initCode)
System.arraycopy(sha3InitCode, 0, data, offset, sha3InitCode.length)

val addr = crypto.kec256(data)
Address(addr)
}

def mergeRaceConditions(that: W): W

def copy: W
Expand Down

0 comments on commit a082d0d

Please sign in to comment.