mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-03 15:55:47 +00:00
change 'BaseComputation' to 'Computation'
This commit is contained in:
parent
79df931234
commit
0b99b76cd1
@ -35,7 +35,7 @@ template balance(addressDb: ReadOnlyStateDb, address: EthAddress): GasInt =
|
|||||||
addressDb.getBalance(address).truncate(int64)
|
addressDb.getBalance(address).truncate(int64)
|
||||||
|
|
||||||
proc binarySearchGas(vmState: var BaseVMState, transaction: Transaction, sender: EthAddress, gasPrice: GasInt, tolerance = 1): GasInt =
|
proc binarySearchGas(vmState: var BaseVMState, transaction: Transaction, sender: EthAddress, gasPrice: GasInt, tolerance = 1): GasInt =
|
||||||
proc dummyComputation(vmState: var BaseVMState, transaction: Transaction, sender: EthAddress): BaseComputation =
|
proc dummyComputation(vmState: var BaseVMState, transaction: Transaction, sender: EthAddress): Computation =
|
||||||
let recipient = transaction.getRecipient()
|
let recipient = transaction.getRecipient()
|
||||||
# Note that vmState may be altered
|
# Note that vmState may be altered
|
||||||
setupComputation(
|
setupComputation(
|
||||||
@ -276,7 +276,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||||||
value: UInt256, data: seq[byte],
|
value: UInt256, data: seq[byte],
|
||||||
sender, destination: EthAddress,
|
sender, destination: EthAddress,
|
||||||
gasLimit, gasPrice: GasInt,
|
gasLimit, gasPrice: GasInt,
|
||||||
contractCreation: bool): BaseComputation =
|
contractCreation: bool): Computation =
|
||||||
let
|
let
|
||||||
# Handle optional defaults.
|
# Handle optional defaults.
|
||||||
message = Message(
|
message = Message(
|
||||||
@ -292,7 +292,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||||||
data: data,
|
data: data,
|
||||||
code: vmState.readOnlyStateDB.getCode(destination).toSeq
|
code: vmState.readOnlyStateDB.getCode(destination).toSeq
|
||||||
)
|
)
|
||||||
result = newBaseComputation(vmState, message)
|
result = newComputation(vmState, message)
|
||||||
|
|
||||||
rpcsrv.rpc("eth_call") do(call: EthCall, quantityTag: string) -> HexDataStr:
|
rpcsrv.rpc("eth_call") do(call: EthCall, quantityTag: string) -> HexDataStr:
|
||||||
## Executes a new message call immediately without creating a transaction on the block chain.
|
## Executes a new message call immediately without creating a transaction on the block chain.
|
||||||
|
@ -17,7 +17,7 @@ import
|
|||||||
logScope:
|
logScope:
|
||||||
topics = "vm computation"
|
topics = "vm computation"
|
||||||
|
|
||||||
proc newBaseComputation*(vmState: BaseVMState, message: Message, forkOverride=none(Fork)): BaseComputation =
|
proc newComputation*(vmState: BaseVMState, message: Message, forkOverride=none(Fork)): Computation =
|
||||||
new result
|
new result
|
||||||
result.vmState = vmState
|
result.vmState = vmState
|
||||||
result.msg = message
|
result.msg = message
|
||||||
@ -37,213 +37,213 @@ proc newBaseComputation*(vmState: BaseVMState, message: Message, forkOverride=no
|
|||||||
result.nextProc = proc() =
|
result.nextProc = proc() =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc isOriginComputation*(c: BaseComputation): bool =
|
proc isOriginComputation*(c: Computation): bool =
|
||||||
# Is this computation the computation initiated by a transaction
|
# Is this computation the computation initiated by a transaction
|
||||||
c.msg.isOrigin
|
c.msg.isOrigin
|
||||||
|
|
||||||
template isSuccess*(c: BaseComputation): bool =
|
template isSuccess*(c: Computation): bool =
|
||||||
c.error.isNil
|
c.error.isNil
|
||||||
|
|
||||||
template isError*(c: BaseComputation): bool =
|
template isError*(c: Computation): bool =
|
||||||
not c.isSuccess
|
not c.isSuccess
|
||||||
|
|
||||||
func shouldBurnGas*(c: BaseComputation): bool =
|
func shouldBurnGas*(c: Computation): bool =
|
||||||
c.isError and c.error.burnsGas
|
c.isError and c.error.burnsGas
|
||||||
|
|
||||||
func shouldEraseReturnData*(c: BaseComputation): bool =
|
func shouldEraseReturnData*(c: Computation): bool =
|
||||||
c.isError and c.error.erasesReturnData
|
c.isError and c.error.erasesReturnData
|
||||||
|
|
||||||
func bytesToHex(x: openarray[byte]): string {.inline.} =
|
func bytesToHex(x: openarray[byte]): string {.inline.} =
|
||||||
## TODO: use seq[byte] for raw data and delete this proc
|
## TODO: use seq[byte] for raw data and delete this proc
|
||||||
foldl(x, a & b.int.toHex(2).toLowerAscii, "0x")
|
foldl(x, a & b.int.toHex(2).toLowerAscii, "0x")
|
||||||
|
|
||||||
func output*(c: BaseComputation): seq[byte] =
|
func output*(c: Computation): seq[byte] =
|
||||||
if c.shouldEraseReturnData:
|
if c.shouldEraseReturnData:
|
||||||
@[]
|
@[]
|
||||||
else:
|
else:
|
||||||
c.rawOutput
|
c.rawOutput
|
||||||
|
|
||||||
func `output=`*(c: BaseComputation, value: openarray[byte]) =
|
func `output=`*(c: Computation, value: openarray[byte]) =
|
||||||
c.rawOutput = @value
|
c.rawOutput = @value
|
||||||
|
|
||||||
proc outputHex*(c: BaseComputation): string =
|
proc outputHex*(c: Computation): string =
|
||||||
if c.shouldEraseReturnData:
|
if c.shouldEraseReturnData:
|
||||||
return "0x"
|
return "0x"
|
||||||
c.rawOutput.bytesToHex
|
c.rawOutput.bytesToHex
|
||||||
|
|
||||||
proc isSuicided*(c: BaseComputation, address: EthAddress): bool =
|
proc isSuicided*(c: Computation, address: EthAddress): bool =
|
||||||
result = address in c.suicides
|
result = address in c.suicides
|
||||||
|
|
||||||
proc snapshot*(comp: BaseComputation) =
|
proc snapshot*(c: Computation) =
|
||||||
comp.dbsnapshot.transaction = comp.vmState.chaindb.db.beginTransaction()
|
c.dbsnapshot.transaction = c.vmState.chaindb.db.beginTransaction()
|
||||||
comp.dbsnapshot.intermediateRoot = comp.vmState.accountDb.rootHash
|
c.dbsnapshot.intermediateRoot = c.vmState.accountDb.rootHash
|
||||||
|
|
||||||
proc commit*(comp: BaseComputation) =
|
proc commit*(c: Computation) =
|
||||||
comp.dbsnapshot.transaction.commit()
|
c.dbsnapshot.transaction.commit()
|
||||||
|
|
||||||
proc dispose*(comp: BaseComputation) {.inline.} =
|
proc dispose*(c: Computation) {.inline.} =
|
||||||
comp.dbsnapshot.transaction.dispose()
|
c.dbsnapshot.transaction.dispose()
|
||||||
|
|
||||||
proc rollback*(comp: BaseComputation) =
|
proc rollback*(c: Computation) =
|
||||||
comp.dbsnapshot.transaction.rollback()
|
c.dbsnapshot.transaction.rollback()
|
||||||
comp.vmState.accountDb.rootHash = comp.dbsnapshot.intermediateRoot
|
c.vmState.accountDb.rootHash = c.dbsnapshot.intermediateRoot
|
||||||
|
|
||||||
proc setError*(comp: BaseComputation, msg: string, burnsGas = false) {.inline.} =
|
proc setError*(c: Computation, msg: string, burnsGas = false) {.inline.} =
|
||||||
comp.error = Error(info: msg, burnsGas: burnsGas)
|
c.error = Error(info: msg, burnsGas: burnsGas)
|
||||||
|
|
||||||
proc writeContract*(computation: BaseComputation, fork: Fork): bool {.gcsafe.} =
|
proc writeContract*(c: Computation, fork: Fork): bool {.gcsafe.} =
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
let contractCode = computation.output
|
let contractCode = c.output
|
||||||
if contractCode.len == 0: return
|
if contractCode.len == 0: return
|
||||||
|
|
||||||
if fork >= FkSpurious and contractCode.len >= EIP170_CODE_SIZE_LIMIT:
|
if fork >= FkSpurious and contractCode.len >= EIP170_CODE_SIZE_LIMIT:
|
||||||
debug "Contract code size exceeds EIP170", limit=EIP170_CODE_SIZE_LIMIT, actual=contractCode.len
|
debug "Contract code size exceeds EIP170", limit=EIP170_CODE_SIZE_LIMIT, actual=contractCode.len
|
||||||
return false
|
return false
|
||||||
|
|
||||||
let storageAddr = computation.msg.contractAddress
|
let storageAddr = c.msg.contractAddress
|
||||||
if computation.isSuicided(storageAddr): return
|
if c.isSuicided(storageAddr): return
|
||||||
|
|
||||||
let gasParams = GasParams(kind: Create, cr_memLength: contractCode.len)
|
let gasParams = GasParams(kind: Create, cr_memLength: contractCode.len)
|
||||||
let codeCost = computation.gasCosts[Create].c_handler(0.u256, gasParams).gasCost
|
let codeCost = c.gasCosts[Create].c_handler(0.u256, gasParams).gasCost
|
||||||
if computation.gasMeter.gasRemaining >= codeCost:
|
if c.gasMeter.gasRemaining >= codeCost:
|
||||||
computation.gasMeter.consumeGas(codeCost, reason = "Write contract code for CREATE")
|
c.gasMeter.consumeGas(codeCost, reason = "Write contract code for CREATE")
|
||||||
computation.vmState.mutateStateDb:
|
c.vmState.mutateStateDb:
|
||||||
db.setCode(storageAddr, contractCode.toRange)
|
db.setCode(storageAddr, contractCode.toRange)
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
if fork < FkHomestead or fork >= FkByzantium: computation.output = @[]
|
if fork < FkHomestead or fork >= FkByzantium: c.output = @[]
|
||||||
result = false
|
result = false
|
||||||
|
|
||||||
proc transferBalance(computation: BaseComputation, opCode: static[Op]) =
|
proc transferBalance(c: Computation, opCode: static[Op]) =
|
||||||
let senderBalance = computation.vmState.readOnlyStateDb().
|
let senderBalance = c.vmState.readOnlyStateDb().
|
||||||
getBalance(computation.msg.sender)
|
getBalance(c.msg.sender)
|
||||||
|
|
||||||
if senderBalance < computation.msg.value:
|
if senderBalance < c.msg.value:
|
||||||
computation.setError(&"insufficient funds available={senderBalance}, needed={computation.msg.value}")
|
c.setError(&"insufficient funds available={senderBalance}, needed={c.msg.value}")
|
||||||
return
|
return
|
||||||
|
|
||||||
when opCode in {Call, Create}:
|
when opCode in {Call, Create}:
|
||||||
computation.vmState.mutateStateDb:
|
c.vmState.mutateStateDb:
|
||||||
db.subBalance(computation.msg.sender, computation.msg.value)
|
db.subBalance(c.msg.sender, c.msg.value)
|
||||||
db.addBalance(computation.msg.contractAddress, computation.msg.value)
|
db.addBalance(c.msg.contractAddress, c.msg.value)
|
||||||
|
|
||||||
template continuation*(comp: BaseComputation, body: untyped) =
|
template continuation*(c: Computation, body: untyped) =
|
||||||
# this is a helper template to implement continuation
|
# this is a helper template to implement continuation
|
||||||
# passing and convert all recursion into tail call
|
# passing and convert all recursion into tail call
|
||||||
var tmpNext = comp.nextProc
|
var tmpNext = c.nextProc
|
||||||
comp.nextProc = proc() {.gcsafe.} =
|
c.nextProc = proc() {.gcsafe.} =
|
||||||
body
|
body
|
||||||
tmpNext()
|
tmpNext()
|
||||||
|
|
||||||
proc initAddress(x: int): EthAddress {.compileTime.} = result[19] = x.byte
|
proc initAddress(x: int): EthAddress {.compileTime.} = result[19] = x.byte
|
||||||
const ripemdAddr = initAddress(3)
|
const ripemdAddr = initAddress(3)
|
||||||
|
|
||||||
proc postExecuteVM(computation: BaseComputation, opCode: static[Op]) {.gcsafe.} =
|
proc postExecuteVM(c: Computation, opCode: static[Op]) {.gcsafe.} =
|
||||||
when opCode == Create:
|
when opCode == Create:
|
||||||
if computation.isSuccess:
|
if c.isSuccess:
|
||||||
let fork = computation.fork
|
let fork = c.fork
|
||||||
let contractFailed = not computation.writeContract(fork)
|
let contractFailed = not c.writeContract(fork)
|
||||||
if contractFailed and fork >= FkHomestead:
|
if contractFailed and fork >= FkHomestead:
|
||||||
computation.setError(&"writeContract failed, depth={computation.msg.depth}", true)
|
c.setError(&"writeContract failed, depth={c.msg.depth}", true)
|
||||||
|
|
||||||
if computation.isSuccess:
|
if c.isSuccess:
|
||||||
computation.commit()
|
c.commit()
|
||||||
else:
|
else:
|
||||||
computation.rollback()
|
c.rollback()
|
||||||
|
|
||||||
proc executeOpcodes*(computation: BaseComputation) {.gcsafe.}
|
proc executeOpcodes*(c: Computation) {.gcsafe.}
|
||||||
|
|
||||||
proc applyMessage*(computation: BaseComputation, opCode: static[Op]) =
|
proc applyMessage*(c: Computation, opCode: static[Op]) =
|
||||||
if computation.msg.depth > MaxCallDepth:
|
if c.msg.depth > MaxCallDepth:
|
||||||
computation.setError(&"Stack depth limit reached depth={computation.msg.depth}")
|
c.setError(&"Stack depth limit reached depth={c.msg.depth}")
|
||||||
computation.nextProc()
|
c.nextProc()
|
||||||
return
|
return
|
||||||
|
|
||||||
computation.snapshot()
|
c.snapshot()
|
||||||
defer:
|
defer:
|
||||||
computation.dispose()
|
c.dispose()
|
||||||
|
|
||||||
# EIP161 nonce incrementation
|
# EIP161 nonce incrementation
|
||||||
when opCode in {Create, Create2}:
|
when opCode in {Create, Create2}:
|
||||||
if computation.fork >= FkSpurious:
|
if c.fork >= FkSpurious:
|
||||||
computation.vmState.mutateStateDb:
|
c.vmState.mutateStateDb:
|
||||||
db.incNonce(computation.msg.contractAddress)
|
db.incNonce(c.msg.contractAddress)
|
||||||
if computation.fork >= FkByzantium:
|
if c.fork >= FkByzantium:
|
||||||
# RevertInCreateInInit.json
|
# RevertInCreateInInit.json
|
||||||
db.setStorageRoot(computation.msg.contractAddress, emptyRlpHash)
|
db.setStorageRoot(c.msg.contractAddress, emptyRlpHash)
|
||||||
|
|
||||||
when opCode in {CallCode, Call, Create}:
|
when opCode in {CallCode, Call, Create}:
|
||||||
computation.transferBalance(opCode)
|
c.transferBalance(opCode)
|
||||||
if computation.isError():
|
if c.isError():
|
||||||
computation.rollback()
|
c.rollback()
|
||||||
computation.nextProc()
|
c.nextProc()
|
||||||
return
|
return
|
||||||
|
|
||||||
if computation.gasMeter.gasRemaining < 0:
|
if c.gasMeter.gasRemaining < 0:
|
||||||
computation.commit()
|
c.commit()
|
||||||
computation.nextProc()
|
c.nextProc()
|
||||||
return
|
return
|
||||||
|
|
||||||
continuation(computation):
|
continuation(c):
|
||||||
postExecuteVM(computation, opCode)
|
postExecuteVM(c, opCode)
|
||||||
|
|
||||||
executeOpcodes(computation)
|
executeOpcodes(c)
|
||||||
|
|
||||||
proc addChildComputation*(computation: BaseComputation, child: BaseComputation) =
|
proc addChildComputation*(c, child: Computation) =
|
||||||
if child.isError or computation.fork == FKIstanbul:
|
if child.isError or c.fork == FKIstanbul:
|
||||||
if not child.msg.isCreate:
|
if not child.msg.isCreate:
|
||||||
if child.msg.contractAddress == ripemdAddr:
|
if child.msg.contractAddress == ripemdAddr:
|
||||||
child.vmState.touchedAccounts.incl child.msg.contractAddress
|
child.vmState.touchedAccounts.incl child.msg.contractAddress
|
||||||
|
|
||||||
if child.isError:
|
if child.isError:
|
||||||
if child.shouldBurnGas:
|
if child.shouldBurnGas:
|
||||||
computation.returnData = @[]
|
c.returnData = @[]
|
||||||
else:
|
else:
|
||||||
computation.returnData = child.output
|
c.returnData = child.output
|
||||||
else:
|
else:
|
||||||
if child.msg.isCreate:
|
if child.msg.isCreate:
|
||||||
computation.returnData = @[]
|
c.returnData = @[]
|
||||||
else:
|
else:
|
||||||
computation.returnData = child.output
|
c.returnData = child.output
|
||||||
child.touchedAccounts.incl child.msg.contractAddress
|
child.touchedAccounts.incl child.msg.contractAddress
|
||||||
computation.logEntries.add child.logEntries
|
c.logEntries.add child.logEntries
|
||||||
computation.gasMeter.refundGas(child.gasMeter.gasRefunded)
|
c.gasMeter.refundGas(child.gasMeter.gasRefunded)
|
||||||
computation.suicides.incl child.suicides
|
c.suicides.incl child.suicides
|
||||||
computation.touchedAccounts.incl child.touchedAccounts
|
c.touchedAccounts.incl child.touchedAccounts
|
||||||
|
|
||||||
if not child.shouldBurnGas:
|
if not child.shouldBurnGas:
|
||||||
computation.gasMeter.returnGas(child.gasMeter.gasRemaining)
|
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
|
||||||
|
|
||||||
proc registerAccountForDeletion*(c: BaseComputation, beneficiary: EthAddress) =
|
proc registerAccountForDeletion*(c: Computation, beneficiary: EthAddress) =
|
||||||
c.touchedAccounts.incl beneficiary
|
c.touchedAccounts.incl beneficiary
|
||||||
c.suicides.incl(c.msg.contractAddress)
|
c.suicides.incl(c.msg.contractAddress)
|
||||||
|
|
||||||
proc addLogEntry*(c: BaseComputation, log: Log) {.inline.} =
|
proc addLogEntry*(c: Computation, log: Log) {.inline.} =
|
||||||
c.logEntries.add(log)
|
c.logEntries.add(log)
|
||||||
|
|
||||||
iterator accountsForDeletion*(c: BaseComputation): EthAddress =
|
iterator accountsForDeletion*(c: Computation): EthAddress =
|
||||||
if c.isSuccess:
|
if c.isSuccess:
|
||||||
for address in c.suicides:
|
for address in c.suicides:
|
||||||
yield address
|
yield address
|
||||||
|
|
||||||
proc getGasRefund*(c: BaseComputation): GasInt =
|
proc getGasRefund*(c: Computation): GasInt =
|
||||||
if c.isSuccess:
|
if c.isSuccess:
|
||||||
result = c.gasMeter.gasRefunded
|
result = c.gasMeter.gasRefunded
|
||||||
|
|
||||||
proc getGasUsed*(c: BaseComputation): GasInt =
|
proc getGasUsed*(c: Computation): GasInt =
|
||||||
if c.shouldBurnGas:
|
if c.shouldBurnGas:
|
||||||
result = c.msg.gas
|
result = c.msg.gas
|
||||||
else:
|
else:
|
||||||
result = max(0, c.msg.gas - c.gasMeter.gasRemaining)
|
result = max(0, c.msg.gas - c.gasMeter.gasRemaining)
|
||||||
|
|
||||||
proc getGasRemaining*(c: BaseComputation): GasInt =
|
proc getGasRemaining*(c: Computation): GasInt =
|
||||||
if c.shouldBurnGas:
|
if c.shouldBurnGas:
|
||||||
result = 0
|
result = 0
|
||||||
else:
|
else:
|
||||||
result = c.gasMeter.gasRemaining
|
result = c.gasMeter.gasRemaining
|
||||||
|
|
||||||
proc collectTouchedAccounts*(c: BaseComputation) =
|
proc collectTouchedAccounts*(c: Computation) =
|
||||||
## Collect all of the accounts that *may* need to be deleted based on EIP161:
|
## Collect all of the accounts that *may* need to be deleted based on EIP161:
|
||||||
## https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md
|
## https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md
|
||||||
## also see: https://github.com/ethereum/EIPs/issues/716
|
## also see: https://github.com/ethereum/EIPs/issues/716
|
||||||
@ -259,19 +259,19 @@ proc collectTouchedAccounts*(c: BaseComputation) =
|
|||||||
if c.msg.contractAddress == ripemdAddr:
|
if c.msg.contractAddress == ripemdAddr:
|
||||||
c.vmState.touchedAccounts.incl c.msg.contractAddress
|
c.vmState.touchedAccounts.incl c.msg.contractAddress
|
||||||
|
|
||||||
proc tracingEnabled*(c: BaseComputation): bool =
|
proc tracingEnabled*(c: Computation): bool =
|
||||||
c.vmState.tracingEnabled
|
c.vmState.tracingEnabled
|
||||||
|
|
||||||
proc traceOpCodeStarted*(c: BaseComputation, op: Op): int =
|
proc traceOpCodeStarted*(c: Computation, op: Op): int =
|
||||||
c.vmState.tracer.traceOpCodeStarted(c, op)
|
c.vmState.tracer.traceOpCodeStarted(c, op)
|
||||||
|
|
||||||
proc traceOpCodeEnded*(c: BaseComputation, op: Op, lastIndex: int) =
|
proc traceOpCodeEnded*(c: Computation, op: Op, lastIndex: int) =
|
||||||
c.vmState.tracer.traceOpCodeEnded(c, op, lastIndex)
|
c.vmState.tracer.traceOpCodeEnded(c, op, lastIndex)
|
||||||
|
|
||||||
proc traceError*(c: BaseComputation) =
|
proc traceError*(c: Computation) =
|
||||||
c.vmState.tracer.traceError(c)
|
c.vmState.tracer.traceError(c)
|
||||||
|
|
||||||
proc prepareTracer*(c: BaseComputation) =
|
proc prepareTracer*(c: Computation) =
|
||||||
c.vmState.tracer.prepare(c.msg.depth)
|
c.vmState.tracer.prepare(c.msg.depth)
|
||||||
|
|
||||||
include interpreter_dispatch
|
include interpreter_dispatch
|
||||||
|
@ -22,7 +22,7 @@ logScope:
|
|||||||
|
|
||||||
template push(x: typed) {.dirty.} =
|
template push(x: typed) {.dirty.} =
|
||||||
## Push an expression on the computation stack
|
## Push an expression on the computation stack
|
||||||
computation.stack.push x
|
c.stack.push x
|
||||||
|
|
||||||
# ##################################
|
# ##################################
|
||||||
# 0s: Stop and Arithmetic Operations
|
# 0s: Stop and Arithmetic Operations
|
||||||
@ -94,8 +94,8 @@ op mulmod, inline = true, lhs, rhs, modulus:
|
|||||||
|
|
||||||
op exp, inline = true, base, exponent:
|
op exp, inline = true, base, exponent:
|
||||||
## 0x0A, Exponentiation
|
## 0x0A, Exponentiation
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[Exp].d_handler(exponent),
|
c.gasCosts[Exp].d_handler(exponent),
|
||||||
reason="EXP: exponent bytes"
|
reason="EXP: exponent bytes"
|
||||||
)
|
)
|
||||||
push:
|
push:
|
||||||
@ -196,18 +196,18 @@ op sha3, inline = true, startPos, length:
|
|||||||
if pos < 0 or len < 0 or pos > 2147483648:
|
if pos < 0 or len < 0 or pos > 2147483648:
|
||||||
raise newException(OutOfBoundsRead, "Out of bounds memory access")
|
raise newException(OutOfBoundsRead, "Out of bounds memory access")
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[Op.Sha3].m_handler(computation.memory.len, pos, len),
|
c.gasCosts[Op.Sha3].m_handler(c.memory.len, pos, len),
|
||||||
reason="SHA3: word gas cost"
|
reason="SHA3: word gas cost"
|
||||||
)
|
)
|
||||||
|
|
||||||
computation.memory.extend(pos, len)
|
c.memory.extend(pos, len)
|
||||||
let endRange = min(pos + len, computation.memory.len) - 1
|
let endRange = min(pos + len, c.memory.len) - 1
|
||||||
if endRange == -1 or pos >= computation.memory.len:
|
if endRange == -1 or pos >= c.memory.len:
|
||||||
push(EMPTY_SHA3)
|
push(EMPTY_SHA3)
|
||||||
else:
|
else:
|
||||||
push:
|
push:
|
||||||
keccak256.digest computation.memory.bytes.toOpenArray(pos, endRange)
|
keccak256.digest c.memory.bytes.toOpenArray(pos, endRange)
|
||||||
|
|
||||||
# ##########################################
|
# ##########################################
|
||||||
# 30s: Environmental Information
|
# 30s: Environmental Information
|
||||||
@ -231,45 +231,45 @@ proc writePaddedResult(mem: var Memory,
|
|||||||
|
|
||||||
op address, inline = true:
|
op address, inline = true:
|
||||||
## 0x30, Get address of currently executing account.
|
## 0x30, Get address of currently executing account.
|
||||||
push: computation.msg.contractAddress
|
push: c.msg.contractAddress
|
||||||
|
|
||||||
op balance, inline = true:
|
op balance, inline = true:
|
||||||
## 0x31, Get balance of the given account.
|
## 0x31, Get balance of the given account.
|
||||||
let address = computation.stack.popAddress()
|
let address = c.stack.popAddress()
|
||||||
push: computation.vmState.readOnlyStateDB.getBalance(address)
|
push: c.vmState.readOnlyStateDB.getBalance(address)
|
||||||
|
|
||||||
op origin, inline = true:
|
op origin, inline = true:
|
||||||
## 0x32, Get execution origination address.
|
## 0x32, Get execution origination address.
|
||||||
push: computation.msg.origin
|
push: c.msg.origin
|
||||||
|
|
||||||
op caller, inline = true:
|
op caller, inline = true:
|
||||||
## 0x33, Get caller address.
|
## 0x33, Get caller address.
|
||||||
push: computation.msg.sender
|
push: c.msg.sender
|
||||||
|
|
||||||
op callValue, inline = true:
|
op callValue, inline = true:
|
||||||
## 0x34, Get deposited value by the instruction/transaction
|
## 0x34, Get deposited value by the instruction/transaction
|
||||||
## responsible for this execution
|
## responsible for this execution
|
||||||
push: computation.msg.value
|
push: c.msg.value
|
||||||
|
|
||||||
op callDataLoad, inline = false, startPos:
|
op callDataLoad, inline = false, startPos:
|
||||||
## 0x35, Get input data of current environment
|
## 0x35, Get input data of current environment
|
||||||
let start = startPos.cleanMemRef
|
let start = startPos.cleanMemRef
|
||||||
if start >= computation.msg.data.len:
|
if start >= c.msg.data.len:
|
||||||
push: 0
|
push: 0
|
||||||
return
|
return
|
||||||
|
|
||||||
# If the data does not take 32 bytes, pad with zeros
|
# If the data does not take 32 bytes, pad with zeros
|
||||||
let endRange = min(computation.msg.data.len - 1, start + 31)
|
let endRange = min(c.msg.data.len - 1, start + 31)
|
||||||
let presentBytes = endRange - start
|
let presentBytes = endRange - start
|
||||||
# We rely on value being initialized with 0 by default
|
# We rely on value being initialized with 0 by default
|
||||||
var value: array[32, byte]
|
var value: array[32, byte]
|
||||||
value[0 .. presentBytes] = computation.msg.data.toOpenArray(start, endRange)
|
value[0 .. presentBytes] = c.msg.data.toOpenArray(start, endRange)
|
||||||
|
|
||||||
push: value
|
push: value
|
||||||
|
|
||||||
op callDataSize, inline = true:
|
op callDataSize, inline = true:
|
||||||
## 0x36, Get size of input data in current environment.
|
## 0x36, Get size of input data in current environment.
|
||||||
push: computation.msg.data.len.u256
|
push: c.msg.data.len.u256
|
||||||
|
|
||||||
op callDataCopy, inline = false, memStartPos, copyStartPos, size:
|
op callDataCopy, inline = false, memStartPos, copyStartPos, size:
|
||||||
## 0x37, Copy input data in current environment to memory.
|
## 0x37, Copy input data in current environment to memory.
|
||||||
@ -277,15 +277,15 @@ op callDataCopy, inline = false, memStartPos, copyStartPos, size:
|
|||||||
|
|
||||||
let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[CallDataCopy].m_handler(computation.memory.len, memPos, len),
|
c.gasCosts[CallDataCopy].m_handler(c.memory.len, memPos, len),
|
||||||
reason="CallDataCopy fee")
|
reason="CallDataCopy fee")
|
||||||
|
|
||||||
computation.memory.writePaddedResult(computation.msg.data, memPos, copyPos, len)
|
c.memory.writePaddedResult(c.msg.data, memPos, copyPos, len)
|
||||||
|
|
||||||
op codeSize, inline = true:
|
op codeSize, inline = true:
|
||||||
## 0x38, Get size of code running in current environment.
|
## 0x38, Get size of code running in current environment.
|
||||||
push: computation.code.len
|
push: c.code.len
|
||||||
|
|
||||||
op codeCopy, inline = false, memStartPos, copyStartPos, size:
|
op codeCopy, inline = false, memStartPos, copyStartPos, size:
|
||||||
## 0x39, Copy code running in current environment to memory.
|
## 0x39, Copy code running in current environment to memory.
|
||||||
@ -293,196 +293,196 @@ op codeCopy, inline = false, memStartPos, copyStartPos, size:
|
|||||||
|
|
||||||
let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[CodeCopy].m_handler(computation.memory.len, memPos, len),
|
c.gasCosts[CodeCopy].m_handler(c.memory.len, memPos, len),
|
||||||
reason="CodeCopy fee")
|
reason="CodeCopy fee")
|
||||||
|
|
||||||
computation.memory.writePaddedResult(computation.code.bytes, memPos, copyPos, len)
|
c.memory.writePaddedResult(c.code.bytes, memPos, copyPos, len)
|
||||||
|
|
||||||
op gasprice, inline = true:
|
op gasprice, inline = true:
|
||||||
## 0x3A, Get price of gas in current environment.
|
## 0x3A, Get price of gas in current environment.
|
||||||
push: computation.msg.gasPrice
|
push: c.msg.gasPrice
|
||||||
|
|
||||||
op extCodeSize, inline = true:
|
op extCodeSize, inline = true:
|
||||||
## 0x3b, Get size of an account's code
|
## 0x3b, Get size of an account's code
|
||||||
let account = computation.stack.popAddress()
|
let account = c.stack.popAddress()
|
||||||
let codeSize = computation.vmState.readOnlyStateDB.getCode(account).len
|
let codeSize = c.vmState.readOnlyStateDB.getCode(account).len
|
||||||
push uint(codeSize)
|
push uint(codeSize)
|
||||||
|
|
||||||
op extCodeCopy, inline = true:
|
op extCodeCopy, inline = true:
|
||||||
## 0x3c, Copy an account's code to memory.
|
## 0x3c, Copy an account's code to memory.
|
||||||
let account = computation.stack.popAddress()
|
let account = c.stack.popAddress()
|
||||||
let (memStartPos, codeStartPos, size) = computation.stack.popInt(3)
|
let (memStartPos, codeStartPos, size) = c.stack.popInt(3)
|
||||||
let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef)
|
let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef)
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[ExtCodeCopy].m_handler(computation.memory.len, memPos, len),
|
c.gasCosts[ExtCodeCopy].m_handler(c.memory.len, memPos, len),
|
||||||
reason="ExtCodeCopy fee")
|
reason="ExtCodeCopy fee")
|
||||||
|
|
||||||
let codeBytes = computation.vmState.readOnlyStateDB.getCode(account)
|
let codeBytes = c.vmState.readOnlyStateDB.getCode(account)
|
||||||
computation.memory.writePaddedResult(codeBytes.toOpenArray, memPos, codePos, len)
|
c.memory.writePaddedResult(codeBytes.toOpenArray, memPos, codePos, len)
|
||||||
|
|
||||||
op returnDataSize, inline = true:
|
op returnDataSize, inline = true:
|
||||||
## 0x3d, Get size of output data from the previous call from the current environment.
|
## 0x3d, Get size of output data from the previous call from the current environment.
|
||||||
push: computation.returnData.len
|
push: c.returnData.len
|
||||||
|
|
||||||
op returnDataCopy, inline = false, memStartPos, copyStartPos, size:
|
op returnDataCopy, inline = false, memStartPos, copyStartPos, size:
|
||||||
## 0x3e, Copy output data from the previous call to memory.
|
## 0x3e, Copy output data from the previous call to memory.
|
||||||
let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
||||||
let gasCost = computation.gasCosts[ReturnDataCopy].m_handler(computation.memory.len, memPos, len)
|
let gasCost = c.gasCosts[ReturnDataCopy].m_handler(c.memory.len, memPos, len)
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
gasCost,
|
gasCost,
|
||||||
reason="returnDataCopy fee")
|
reason="returnDataCopy fee")
|
||||||
|
|
||||||
if copyPos + len > computation.returnData.len:
|
if copyPos + len > c.returnData.len:
|
||||||
# TODO Geth additionally checks copyPos + len < 64
|
# TODO Geth additionally checks copyPos + len < 64
|
||||||
# Parity uses a saturating addition
|
# Parity uses a saturating addition
|
||||||
# Yellow paper mentions μs[1] + i are not subject to the 2^256 modulo.
|
# Yellow paper mentions μs[1] + i are not subject to the 2^256 modulo.
|
||||||
raise newException(OutOfBoundsRead,
|
raise newException(OutOfBoundsRead,
|
||||||
"Return data length is not sufficient to satisfy request. Asked \n" &
|
"Return data length is not sufficient to satisfy request. Asked \n" &
|
||||||
&"for data from index {copyStartPos} to {copyStartPos + size}. Return data is {computation.returnData.len} in \n" &
|
&"for data from index {copyStartPos} to {copyStartPos + size}. Return data is {c.returnData.len} in \n" &
|
||||||
"length")
|
"length")
|
||||||
|
|
||||||
computation.memory.writePaddedResult(computation.returnData, memPos, copyPos, len)
|
c.memory.writePaddedResult(c.returnData, memPos, copyPos, len)
|
||||||
|
|
||||||
# ##########################################
|
# ##########################################
|
||||||
# 40s: Block Information
|
# 40s: Block Information
|
||||||
|
|
||||||
op blockhash, inline = true, blockNumber:
|
op blockhash, inline = true, blockNumber:
|
||||||
## 0x40, Get the hash of one of the 256 most recent complete blocks.
|
## 0x40, Get the hash of one of the 256 most recent complete blocks.
|
||||||
push: computation.vmState.getAncestorHash(blockNumber.vmWordToBlockNumber)
|
push: c.vmState.getAncestorHash(blockNumber.vmWordToBlockNumber)
|
||||||
|
|
||||||
op coinbase, inline = true:
|
op coinbase, inline = true:
|
||||||
## 0x41, Get the block's beneficiary address.
|
## 0x41, Get the block's beneficiary address.
|
||||||
push: computation.vmState.coinbase
|
push: c.vmState.coinbase
|
||||||
|
|
||||||
op timestamp, inline = true:
|
op timestamp, inline = true:
|
||||||
## 0x42, Get the block's timestamp.
|
## 0x42, Get the block's timestamp.
|
||||||
push: computation.vmState.timestamp.toUnix
|
push: c.vmState.timestamp.toUnix
|
||||||
|
|
||||||
op blocknumber, inline = true:
|
op blocknumber, inline = true:
|
||||||
## 0x43, Get the block's number.
|
## 0x43, Get the block's number.
|
||||||
push: computation.vmState.blockNumber.blockNumberToVmWord
|
push: c.vmState.blockNumber.blockNumberToVmWord
|
||||||
|
|
||||||
op difficulty, inline = true:
|
op difficulty, inline = true:
|
||||||
## 0x44, Get the block's difficulty
|
## 0x44, Get the block's difficulty
|
||||||
push: computation.vmState.difficulty
|
push: c.vmState.difficulty
|
||||||
|
|
||||||
op gasLimit, inline = true:
|
op gasLimit, inline = true:
|
||||||
## 0x45, Get the block's gas limit
|
## 0x45, Get the block's gas limit
|
||||||
push: computation.vmState.gasLimit
|
push: c.vmState.gasLimit
|
||||||
|
|
||||||
op chainId, inline = true:
|
op chainId, inline = true:
|
||||||
## 0x46, Get current chain’s EIP-155 unique identifier.
|
## 0x46, Get current chain’s EIP-155 unique identifier.
|
||||||
# TODO: this is a stub
|
# TODO: this is a stub
|
||||||
push: computation.vmState.chaindb.config.chainId
|
push: c.vmState.chaindb.config.chainId
|
||||||
|
|
||||||
op selfBalance, inline = true:
|
op selfBalance, inline = true:
|
||||||
## 0x47, Get current contract's balance.
|
## 0x47, Get current contract's balance.
|
||||||
let stateDb = computation.vmState.readOnlyStateDb
|
let stateDb = c.vmState.readOnlyStateDb
|
||||||
push: stateDb.getBalance(computation.msg.contractAddress)
|
push: stateDb.getBalance(c.msg.contractAddress)
|
||||||
|
|
||||||
# ##########################################
|
# ##########################################
|
||||||
# 50s: Stack, Memory, Storage and Flow Operations
|
# 50s: Stack, Memory, Storage and Flow Operations
|
||||||
|
|
||||||
op pop, inline = true:
|
op pop, inline = true:
|
||||||
## 0x50, Remove item from stack.
|
## 0x50, Remove item from stack.
|
||||||
discard computation.stack.popInt()
|
discard c.stack.popInt()
|
||||||
|
|
||||||
op mload, inline = true, memStartPos:
|
op mload, inline = true, memStartPos:
|
||||||
## 0x51, Load word from memory
|
## 0x51, Load word from memory
|
||||||
let memPos = memStartPos.cleanMemRef
|
let memPos = memStartPos.cleanMemRef
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[MLoad].m_handler(computation.memory.len, memPos, 32),
|
c.gasCosts[MLoad].m_handler(c.memory.len, memPos, 32),
|
||||||
reason="MLOAD: GasVeryLow + memory expansion"
|
reason="MLOAD: GasVeryLow + memory expansion"
|
||||||
)
|
)
|
||||||
computation.memory.extend(memPos, 32)
|
c.memory.extend(memPos, 32)
|
||||||
|
|
||||||
push: computation.memory.read(memPos, 32) # TODO, should we convert to native endianness?
|
push: c.memory.read(memPos, 32) # TODO, should we convert to native endianness?
|
||||||
|
|
||||||
op mstore, inline = true, memStartPos, value:
|
op mstore, inline = true, memStartPos, value:
|
||||||
## 0x52, Save word to memory
|
## 0x52, Save word to memory
|
||||||
let memPos = memStartPos.cleanMemRef
|
let memPos = memStartPos.cleanMemRef
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[MStore].m_handler(computation.memory.len, memPos, 32),
|
c.gasCosts[MStore].m_handler(c.memory.len, memPos, 32),
|
||||||
reason="MSTORE: GasVeryLow + memory expansion"
|
reason="MSTORE: GasVeryLow + memory expansion"
|
||||||
)
|
)
|
||||||
|
|
||||||
computation.memory.extend(memPos, 32)
|
c.memory.extend(memPos, 32)
|
||||||
computation.memory.write(memPos, value.toByteArrayBE) # is big-endian correct? Parity/Geth do convert
|
c.memory.write(memPos, value.toByteArrayBE) # is big-endian correct? Parity/Geth do convert
|
||||||
|
|
||||||
op mstore8, inline = true, memStartPos, value:
|
op mstore8, inline = true, memStartPos, value:
|
||||||
## 0x53, Save byte to memory
|
## 0x53, Save byte to memory
|
||||||
let memPos = memStartPos.cleanMemRef
|
let memPos = memStartPos.cleanMemRef
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[MStore].m_handler(computation.memory.len, memPos, 1),
|
c.gasCosts[MStore].m_handler(c.memory.len, memPos, 1),
|
||||||
reason="MSTORE8: GasVeryLow + memory expansion"
|
reason="MSTORE8: GasVeryLow + memory expansion"
|
||||||
)
|
)
|
||||||
|
|
||||||
computation.memory.extend(memPos, 1)
|
c.memory.extend(memPos, 1)
|
||||||
computation.memory.write(memPos, [value.toByteArrayBE[31]])
|
c.memory.write(memPos, [value.toByteArrayBE[31]])
|
||||||
|
|
||||||
op sload, inline = true, slot:
|
op sload, inline = true, slot:
|
||||||
## 0x54, Load word from storage.
|
## 0x54, Load word from storage.
|
||||||
|
|
||||||
let (value, _) = computation.vmState.readOnlyStateDB.getStorage(computation.msg.contractAddress, slot)
|
let (value, _) = c.vmState.readOnlyStateDB.getStorage(c.msg.contractAddress, slot)
|
||||||
push(value)
|
push(value)
|
||||||
|
|
||||||
op sstore, inline = false, slot, value:
|
op sstore, inline = false, slot, value:
|
||||||
## 0x55, Save word to storage.
|
## 0x55, Save word to storage.
|
||||||
checkInStaticContext(computation)
|
checkInStaticContext(c)
|
||||||
|
|
||||||
let (currentValue, existing) = computation.vmState.readOnlyStateDB.getStorage(computation.msg.contractAddress, slot)
|
let (currentValue, existing) = c.vmState.readOnlyStateDB.getStorage(c.msg.contractAddress, slot)
|
||||||
|
|
||||||
let
|
let
|
||||||
gasParam = GasParams(kind: Op.Sstore, s_isStorageEmpty: currentValue.isZero)
|
gasParam = GasParams(kind: Op.Sstore, s_isStorageEmpty: currentValue.isZero)
|
||||||
(gasCost, gasRefund) = computation.gasCosts[Sstore].c_handler(value, gasParam)
|
(gasCost, gasRefund) = c.gasCosts[Sstore].c_handler(value, gasParam)
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(gasCost, &"SSTORE: {computation.msg.contractAddress}[{slot}] -> {value} ({currentValue})")
|
c.gasMeter.consumeGas(gasCost, &"SSTORE: {c.msg.contractAddress}[{slot}] -> {value} ({currentValue})")
|
||||||
|
|
||||||
if gasRefund > 0:
|
if gasRefund > 0:
|
||||||
computation.gasMeter.refundGas(gasRefund)
|
c.gasMeter.refundGas(gasRefund)
|
||||||
|
|
||||||
computation.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
db.setStorage(computation.msg.contractAddress, slot, value)
|
db.setStorage(c.msg.contractAddress, slot, value)
|
||||||
|
|
||||||
proc jumpImpl(computation: BaseComputation, jumpTarget: UInt256) =
|
proc jumpImpl(c: Computation, jumpTarget: UInt256) =
|
||||||
if jumpTarget >= computation.code.len.u256:
|
if jumpTarget >= c.code.len.u256:
|
||||||
raise newException(InvalidJumpDestination, "Invalid Jump Destination")
|
raise newException(InvalidJumpDestination, "Invalid Jump Destination")
|
||||||
|
|
||||||
let jt = jumpTarget.truncate(int)
|
let jt = jumpTarget.truncate(int)
|
||||||
computation.code.pc = jt
|
c.code.pc = jt
|
||||||
|
|
||||||
let nextOpcode = computation.code.peek
|
let nextOpcode = c.code.peek
|
||||||
if nextOpcode != JUMPDEST:
|
if nextOpcode != JUMPDEST:
|
||||||
raise newException(InvalidJumpDestination, "Invalid Jump Destination")
|
raise newException(InvalidJumpDestination, "Invalid Jump Destination")
|
||||||
# TODO: next check seems redundant
|
# TODO: next check seems redundant
|
||||||
if not computation.code.isValidOpcode(jt):
|
if not c.code.isValidOpcode(jt):
|
||||||
raise newException(InvalidInstruction, "Jump resulted in invalid instruction")
|
raise newException(InvalidInstruction, "Jump resulted in invalid instruction")
|
||||||
|
|
||||||
op jump, inline = true, jumpTarget:
|
op jump, inline = true, jumpTarget:
|
||||||
## 0x56, Alter the program counter
|
## 0x56, Alter the program counter
|
||||||
jumpImpl(computation, jumpTarget)
|
jumpImpl(c, jumpTarget)
|
||||||
|
|
||||||
op jumpI, inline = true, jumpTarget, testedValue:
|
op jumpI, inline = true, jumpTarget, testedValue:
|
||||||
## 0x57, Conditionally alter the program counter.
|
## 0x57, Conditionally alter the program counter.
|
||||||
if testedValue != 0:
|
if testedValue != 0:
|
||||||
jumpImpl(computation, jumpTarget)
|
jumpImpl(c, jumpTarget)
|
||||||
|
|
||||||
op pc, inline = true:
|
op pc, inline = true:
|
||||||
## 0x58, Get the value of the program counter prior to the increment corresponding to this instruction.
|
## 0x58, Get the value of the program counter prior to the increment corresponding to this instruction.
|
||||||
push: max(computation.code.pc - 1, 0)
|
push: max(c.code.pc - 1, 0)
|
||||||
|
|
||||||
op msize, inline = true:
|
op msize, inline = true:
|
||||||
## 0x59, Get the size of active memory in bytes.
|
## 0x59, Get the size of active memory in bytes.
|
||||||
push: computation.memory.len
|
push: c.memory.len
|
||||||
|
|
||||||
op gas, inline = true:
|
op gas, inline = true:
|
||||||
## 0x5a, Get the amount of available gas, including the corresponding reduction for the cost of this instruction.
|
## 0x5a, Get the amount of available gas, including the corresponding reduction for the cost of this instruction.
|
||||||
push: computation.gasMeter.gasRemaining
|
push: c.gasMeter.gasRemaining
|
||||||
|
|
||||||
op jumpDest, inline = true:
|
op jumpDest, inline = true:
|
||||||
## 0x5b, Mark a valid destination for jumps. This operation has no effect on machine state during execution.
|
## 0x5b, Mark a valid destination for jumps. This operation has no effect on machine state during execution.
|
||||||
@ -502,53 +502,53 @@ genLog()
|
|||||||
# ##########################################
|
# ##########################################
|
||||||
# f0s: System operations.
|
# f0s: System operations.
|
||||||
|
|
||||||
proc canTransfer(computation: BaseComputation, memPos, memLen: int, value: Uint256, opCode: static[Op]): bool =
|
proc canTransfer(c: Computation, memPos, memLen: int, value: Uint256, opCode: static[Op]): bool =
|
||||||
let gasParams = GasParams(kind: Create,
|
let gasParams = GasParams(kind: Create,
|
||||||
cr_currentMemSize: computation.memory.len,
|
cr_currentMemSize: c.memory.len,
|
||||||
cr_memOffset: memPos,
|
cr_memOffset: memPos,
|
||||||
cr_memLength: memLen
|
cr_memLength: memLen
|
||||||
)
|
)
|
||||||
var gasCost = computation.gasCosts[Create].c_handler(1.u256, gasParams).gasCost
|
var gasCost = c.gasCosts[Create].c_handler(1.u256, gasParams).gasCost
|
||||||
let reason = &"CREATE: GasCreate + {memLen} * memory expansion"
|
let reason = &"CREATE: GasCreate + {memLen} * memory expansion"
|
||||||
|
|
||||||
when opCode == Create2:
|
when opCode == Create2:
|
||||||
gasCost = gasCost + computation.gasCosts[Create2].m_handler(0, 0, memLen)
|
gasCost = gasCost + c.gasCosts[Create2].m_handler(0, 0, memLen)
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(gasCost, reason = reason)
|
c.gasMeter.consumeGas(gasCost, reason = reason)
|
||||||
computation.memory.extend(memPos, memLen)
|
c.memory.extend(memPos, memLen)
|
||||||
|
|
||||||
# the sender is childmsg sender, not parent msg sender
|
# the sender is childmsg sender, not parent msg sender
|
||||||
# perhaps we need to move this code somewhere else
|
# perhaps we need to move this code somewhere else
|
||||||
# to avoid confusion
|
# to avoid confusion
|
||||||
let senderBalance =
|
let senderBalance =
|
||||||
computation.vmState.readOnlyStateDb().
|
c.vmState.readOnlyStateDb().
|
||||||
getBalance(computation.msg.contractAddress)
|
getBalance(c.msg.contractAddress)
|
||||||
|
|
||||||
if senderBalance < value:
|
if senderBalance < value:
|
||||||
debug "Computation Failure", reason = "Insufficient funds available to transfer", required = computation.msg.value, balance = senderBalance
|
debug "Computation Failure", reason = "Insufficient funds available to transfer", required = c.msg.value, balance = senderBalance
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# unlike the other MaxCallDepth comparison,
|
# unlike the other MaxCallDepth comparison,
|
||||||
# this one has not been entered child computation
|
# this one has not been entered child computation
|
||||||
# thats why it has `+ 1`
|
# thats why it has `+ 1`
|
||||||
if computation.msg.depth + 1 > MaxCallDepth:
|
if c.msg.depth + 1 > MaxCallDepth:
|
||||||
debug "Computation Failure", reason = "Stack too deep", maximumDepth = MaxCallDepth, depth = computation.msg.depth
|
debug "Computation Failure", reason = "Stack too deep", maximumDepth = MaxCallDepth, depth = c.msg.depth
|
||||||
return false
|
return false
|
||||||
|
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256, opCode: static[Op]): BaseComputation =
|
proc setupCreate(c: Computation, memPos, len: int, value: Uint256, opCode: static[Op]): Computation =
|
||||||
let
|
let
|
||||||
callData = computation.memory.read(memPos, len)
|
callData = c.memory.read(memPos, len)
|
||||||
|
|
||||||
var
|
var
|
||||||
createMsgGas = computation.getGasRemaining()
|
createMsgGas = c.getGasRemaining()
|
||||||
|
|
||||||
if computation.fork >= FkTangerine:
|
if c.fork >= FkTangerine:
|
||||||
createMsgGas -= createMsgGas div 64
|
createMsgGas -= createMsgGas div 64
|
||||||
|
|
||||||
# Consume gas here that will be passed to child
|
# Consume gas here that will be passed to child
|
||||||
computation.gasMeter.consumeGas(createMsgGas, reason="CREATE")
|
c.gasMeter.consumeGas(createMsgGas, reason="CREATE")
|
||||||
|
|
||||||
# Generate new address and check for collisions
|
# Generate new address and check for collisions
|
||||||
var
|
var
|
||||||
@ -557,20 +557,20 @@ proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256,
|
|||||||
|
|
||||||
when opCode == Create:
|
when opCode == Create:
|
||||||
const callKind = evmcCreate
|
const callKind = evmcCreate
|
||||||
computation.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
# Regarding collisions, see: https://github.com/status-im/nimbus/issues/133
|
# Regarding collisions, see: https://github.com/status-im/nimbus/issues/133
|
||||||
# See: https://github.com/ethereum/EIPs/issues/684
|
# See: https://github.com/ethereum/EIPs/issues/684
|
||||||
let creationNonce = db.getNonce(computation.msg.contractAddress)
|
let creationNonce = db.getNonce(c.msg.contractAddress)
|
||||||
db.setNonce(computation.msg.contractAddress, creationNonce + 1)
|
db.setNonce(c.msg.contractAddress, creationNonce + 1)
|
||||||
|
|
||||||
contractAddress = generateAddress(computation.msg.contractAddress, creationNonce)
|
contractAddress = generateAddress(c.msg.contractAddress, creationNonce)
|
||||||
isCollision = db.hasCodeOrNonce(contractAddress)
|
isCollision = db.hasCodeOrNonce(contractAddress)
|
||||||
else:
|
else:
|
||||||
const callKind = evmcCreate2
|
const callKind = evmcCreate2
|
||||||
computation.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
db.incNonce(computation.msg.contractAddress)
|
db.incNonce(c.msg.contractAddress)
|
||||||
let salt = computation.stack.popInt()
|
let salt = c.stack.popInt()
|
||||||
contractAddress = generateSafeAddress(computation.msg.contractAddress, salt, callData)
|
contractAddress = generateSafeAddress(c.msg.contractAddress, salt, callData)
|
||||||
isCollision = db.hasCodeOrNonce(contractAddress)
|
isCollision = db.hasCodeOrNonce(contractAddress)
|
||||||
|
|
||||||
if isCollision:
|
if isCollision:
|
||||||
@ -580,11 +580,11 @@ proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256,
|
|||||||
|
|
||||||
let childMsg = Message(
|
let childMsg = Message(
|
||||||
kind: callKind,
|
kind: callKind,
|
||||||
depth: computation.msg.depth + 1,
|
depth: c.msg.depth + 1,
|
||||||
gas: createMsgGas,
|
gas: createMsgGas,
|
||||||
gasPrice: computation.msg.gasPrice,
|
gasPrice: c.msg.gasPrice,
|
||||||
origin: computation.msg.origin,
|
origin: c.msg.origin,
|
||||||
sender: computation.msg.contractAddress,
|
sender: c.msg.contractAddress,
|
||||||
contractAddress: contractAddress,
|
contractAddress: contractAddress,
|
||||||
codeAddress: CREATE_CONTRACT_ADDRESS,
|
codeAddress: CREATE_CONTRACT_ADDRESS,
|
||||||
value: value,
|
value: value,
|
||||||
@ -592,106 +592,103 @@ proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256,
|
|||||||
code: callData
|
code: callData
|
||||||
)
|
)
|
||||||
|
|
||||||
result = newBaseComputation(
|
result = newComputation(c.vmState, childMsg, some(c.fork))
|
||||||
computation.vmState,
|
|
||||||
childMsg,
|
|
||||||
some(computation.fork))
|
|
||||||
|
|
||||||
template genCreate(callName: untyped, opCode: Op): untyped =
|
template genCreate(callName: untyped, opCode: Op): untyped =
|
||||||
op callName, inline = false, val, startPosition, size:
|
op callName, inline = false, val, startPosition, size:
|
||||||
## 0xf0, Create a new account with associated code.
|
## 0xf0, Create a new account with associated code.
|
||||||
let (memPos, len) = (startPosition.safeInt, size.safeInt)
|
let (memPos, len) = (startPosition.safeInt, size.safeInt)
|
||||||
if not computation.canTransfer(memPos, len, val, opCode):
|
if not c.canTransfer(memPos, len, val, opCode):
|
||||||
push: 0
|
push: 0
|
||||||
return
|
return
|
||||||
|
|
||||||
var childComp = setupCreate(computation, memPos, len, val, opCode)
|
var child = setupCreate(c, memPos, len, val, opCode)
|
||||||
if childComp.isNil: return
|
if child.isNil: return
|
||||||
|
|
||||||
continuation(childComp):
|
continuation(child):
|
||||||
addChildComputation(computation, childComp)
|
addChildComputation(c, child)
|
||||||
|
|
||||||
if childComp.isError:
|
if child.isError:
|
||||||
push: 0
|
push: 0
|
||||||
else:
|
else:
|
||||||
push: childComp.msg.contractAddress
|
push: child.msg.contractAddress
|
||||||
|
|
||||||
checkInStaticContext(computation)
|
checkInStaticContext(c)
|
||||||
childComp.applyMessage(Create)
|
child.applyMessage(Create)
|
||||||
|
|
||||||
genCreate(create, Create)
|
genCreate(create, Create)
|
||||||
genCreate(create2, Create2)
|
genCreate(create2, Create2)
|
||||||
|
|
||||||
proc callParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) =
|
proc callParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) =
|
||||||
let gas = computation.stack.popInt()
|
let gas = c.stack.popInt()
|
||||||
let codeAddress = computation.stack.popAddress()
|
let codeAddress = c.stack.popAddress()
|
||||||
|
|
||||||
let (value,
|
let (value,
|
||||||
memoryInputStartPosition, memoryInputSize,
|
memoryInputStartPosition, memoryInputSize,
|
||||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(5)
|
memoryOutputStartPosition, memoryOutputSize) = c.stack.popInt(5)
|
||||||
|
|
||||||
result = (gas,
|
result = (gas,
|
||||||
value,
|
value,
|
||||||
codeAddress, # contractAddress
|
codeAddress, # contractAddress
|
||||||
computation.msg.contractAddress, # sender
|
c.msg.contractAddress, # sender
|
||||||
codeAddress,
|
codeAddress,
|
||||||
evmcCall,
|
evmcCall,
|
||||||
memoryInputStartPosition,
|
memoryInputStartPosition,
|
||||||
memoryInputSize,
|
memoryInputSize,
|
||||||
memoryOutputStartPosition,
|
memoryOutputStartPosition,
|
||||||
memoryOutputSize,
|
memoryOutputSize,
|
||||||
computation.msg.flags)
|
c.msg.flags)
|
||||||
|
|
||||||
proc callCodeParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) =
|
proc callCodeParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) =
|
||||||
let gas = computation.stack.popInt()
|
let gas = c.stack.popInt()
|
||||||
let codeAddress = computation.stack.popAddress()
|
let codeAddress = c.stack.popAddress()
|
||||||
|
|
||||||
let (value,
|
let (value,
|
||||||
memoryInputStartPosition, memoryInputSize,
|
memoryInputStartPosition, memoryInputSize,
|
||||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(5)
|
memoryOutputStartPosition, memoryOutputSize) = c.stack.popInt(5)
|
||||||
|
|
||||||
result = (gas,
|
result = (gas,
|
||||||
value,
|
value,
|
||||||
computation.msg.contractAddress, # contractAddress
|
c.msg.contractAddress, # contractAddress
|
||||||
computation.msg.contractAddress, # sender
|
c.msg.contractAddress, # sender
|
||||||
codeAddress,
|
codeAddress,
|
||||||
evmcCallCode,
|
evmcCallCode,
|
||||||
memoryInputStartPosition,
|
memoryInputStartPosition,
|
||||||
memoryInputSize,
|
memoryInputSize,
|
||||||
memoryOutputStartPosition,
|
memoryOutputStartPosition,
|
||||||
memoryOutputSize,
|
memoryOutputSize,
|
||||||
computation.msg.flags)
|
c.msg.flags)
|
||||||
|
|
||||||
proc delegateCallParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) =
|
proc delegateCallParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) =
|
||||||
let gas = computation.stack.popInt()
|
let gas = c.stack.popInt()
|
||||||
let codeAddress = computation.stack.popAddress()
|
let codeAddress = c.stack.popAddress()
|
||||||
|
|
||||||
let (memoryInputStartPosition, memoryInputSize,
|
let (memoryInputStartPosition, memoryInputSize,
|
||||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4)
|
memoryOutputStartPosition, memoryOutputSize) = c.stack.popInt(4)
|
||||||
|
|
||||||
result = (gas,
|
result = (gas,
|
||||||
computation.msg.value, # value
|
c.msg.value, # value
|
||||||
computation.msg.contractAddress, # contractAddress
|
c.msg.contractAddress, # contractAddress
|
||||||
computation.msg.sender, # sender
|
c.msg.sender, # sender
|
||||||
codeAddress,
|
codeAddress,
|
||||||
evmcDelegateCall,
|
evmcDelegateCall,
|
||||||
memoryInputStartPosition,
|
memoryInputStartPosition,
|
||||||
memoryInputSize,
|
memoryInputSize,
|
||||||
memoryOutputStartPosition,
|
memoryOutputStartPosition,
|
||||||
memoryOutputSize,
|
memoryOutputSize,
|
||||||
computation.msg.flags)
|
c.msg.flags)
|
||||||
|
|
||||||
proc staticCallParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) =
|
proc staticCallParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) =
|
||||||
let gas = computation.stack.popInt()
|
let gas = c.stack.popInt()
|
||||||
let codeAddress = computation.stack.popAddress()
|
let codeAddress = c.stack.popAddress()
|
||||||
|
|
||||||
let (memoryInputStartPosition, memoryInputSize,
|
let (memoryInputStartPosition, memoryInputSize,
|
||||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4)
|
memoryOutputStartPosition, memoryOutputSize) = c.stack.popInt(4)
|
||||||
|
|
||||||
result = (gas,
|
result = (gas,
|
||||||
0.u256, # value
|
0.u256, # value
|
||||||
codeAddress, # contractAddress
|
codeAddress, # contractAddress
|
||||||
computation.msg.contractAddress, # sender
|
c.msg.contractAddress, # sender
|
||||||
codeAddress,
|
codeAddress,
|
||||||
evmcCall,
|
evmcCall,
|
||||||
memoryInputStartPosition,
|
memoryInputStartPosition,
|
||||||
@ -701,55 +698,55 @@ proc staticCallParams(computation: BaseComputation): (UInt256, UInt256, EthAddre
|
|||||||
emvcStatic) # is_static
|
emvcStatic) # is_static
|
||||||
|
|
||||||
template genCall(callName: untyped, opCode: Op): untyped =
|
template genCall(callName: untyped, opCode: Op): untyped =
|
||||||
proc `callName Setup`(computation: BaseComputation, callNameStr: string): BaseComputation =
|
proc `callName Setup`(c: Computation, callNameStr: string): Computation =
|
||||||
let (gas, value, contractAddress, sender,
|
let (gas, value, contractAddress, sender,
|
||||||
codeAddress, callKind,
|
codeAddress, callKind,
|
||||||
memoryInputStartPosition, memoryInputSize,
|
memoryInputStartPosition, memoryInputSize,
|
||||||
memoryOutputStartPosition, memoryOutputSize,
|
memoryOutputStartPosition, memoryOutputSize,
|
||||||
flags) = `callName Params`(computation)
|
flags) = `callName Params`(c)
|
||||||
|
|
||||||
let (memInPos, memInLen, memOutPos, memOutLen) = (memoryInputStartPosition.cleanMemRef, memoryInputSize.cleanMemRef, memoryOutputStartPosition.cleanMemRef, memoryOutputSize.cleanMemRef)
|
let (memInPos, memInLen, memOutPos, memOutLen) = (memoryInputStartPosition.cleanMemRef, memoryInputSize.cleanMemRef, memoryOutputStartPosition.cleanMemRef, memoryOutputSize.cleanMemRef)
|
||||||
|
|
||||||
let isNewAccount = if computation.fork >= FkSpurious:
|
let isNewAccount = if c.fork >= FkSpurious:
|
||||||
computation.vmState.readOnlyStateDb.isDeadAccount(contractAddress)
|
c.vmState.readOnlyStateDb.isDeadAccount(contractAddress)
|
||||||
else:
|
else:
|
||||||
not computation.vmState.readOnlyStateDb.accountExists(contractAddress)
|
not c.vmState.readOnlyStateDb.accountExists(contractAddress)
|
||||||
|
|
||||||
let (memOffset, memLength) = if calcMemSize(memInPos, memInLen) > calcMemSize(memOutPos, memOutLen):
|
let (memOffset, memLength) = if calcMemSize(memInPos, memInLen) > calcMemSize(memOutPos, memOutLen):
|
||||||
(memInPos, memInLen)
|
(memInPos, memInLen)
|
||||||
else:
|
else:
|
||||||
(memOutPos, memOutLen)
|
(memOutPos, memOutLen)
|
||||||
|
|
||||||
let (childGasFee, childGasLimit) = computation.gasCosts[opCode].c_handler(
|
let (childGasFee, childGasLimit) = c.gasCosts[opCode].c_handler(
|
||||||
value,
|
value,
|
||||||
GasParams(kind: opCode,
|
GasParams(kind: opCode,
|
||||||
c_isNewAccount: isNewAccount,
|
c_isNewAccount: isNewAccount,
|
||||||
c_gasBalance: computation.gasMeter.gasRemaining,
|
c_gasBalance: c.gasMeter.gasRemaining,
|
||||||
c_contractGas: gas,
|
c_contractGas: gas,
|
||||||
c_currentMemSize: computation.memory.len,
|
c_currentMemSize: c.memory.len,
|
||||||
c_memOffset: memOffset,
|
c_memOffset: memOffset,
|
||||||
c_memLength: memLength
|
c_memLength: memLength
|
||||||
))
|
))
|
||||||
|
|
||||||
if childGasFee >= 0:
|
if childGasFee >= 0:
|
||||||
computation.gasMeter.consumeGas(childGasFee, reason = $opCode)
|
c.gasMeter.consumeGas(childGasFee, reason = $opCode)
|
||||||
|
|
||||||
if childGasFee < 0 and childGasLimit <= 0:
|
if childGasFee < 0 and childGasLimit <= 0:
|
||||||
raise newException(OutOfGas, "Gas not enough to perform calculation (" & callNameStr & ")")
|
raise newException(OutOfGas, "Gas not enough to perform calculation (" & callNameStr & ")")
|
||||||
|
|
||||||
computation.memory.extend(memInPos, memInLen)
|
c.memory.extend(memInPos, memInLen)
|
||||||
computation.memory.extend(memOutPos, memOutLen)
|
c.memory.extend(memOutPos, memOutLen)
|
||||||
|
|
||||||
let
|
let
|
||||||
callData = computation.memory.read(memInPos, memInLen)
|
callData = c.memory.read(memInPos, memInLen)
|
||||||
code = computation.vmState.readOnlyStateDb.getCode(codeAddress)
|
code = c.vmState.readOnlyStateDb.getCode(codeAddress)
|
||||||
|
|
||||||
var childMsg = Message(
|
var childMsg = Message(
|
||||||
kind: callKind,
|
kind: callKind,
|
||||||
depth: computation.msg.depth + 1,
|
depth: c.msg.depth + 1,
|
||||||
gas: childGasLimit,
|
gas: childGasLimit,
|
||||||
gasPrice: computation.msg.gasPrice,
|
gasPrice: c.msg.gasPrice,
|
||||||
origin: computation.msg.origin,
|
origin: c.msg.origin,
|
||||||
sender: sender,
|
sender: sender,
|
||||||
contractAddress: contractAddress,
|
contractAddress: contractAddress,
|
||||||
codeAddress: codeAddress,
|
codeAddress: codeAddress,
|
||||||
@ -758,41 +755,38 @@ template genCall(callName: untyped, opCode: Op): untyped =
|
|||||||
code: code.toSeq,
|
code: code.toSeq,
|
||||||
flags: flags)
|
flags: flags)
|
||||||
|
|
||||||
var childComp = newBaseComputation(
|
var child = newComputation(c.vmState, childMsg, some(c.fork))
|
||||||
computation.vmState,
|
|
||||||
childMsg,
|
|
||||||
some(computation.fork))
|
|
||||||
|
|
||||||
computation.memOutPos = memOutPos
|
c.memOutPos = memOutPos
|
||||||
computation.memOutLen = memOutLen
|
c.memOutLen = memOutLen
|
||||||
result = childComp
|
result = child
|
||||||
|
|
||||||
op callName, inline = false:
|
op callName, inline = false:
|
||||||
## CALL, 0xf1, Message-Call into an account
|
## CALL, 0xf1, Message-Call into an account
|
||||||
## CALLCODE, 0xf2, Message-call into this account with an alternative account's code.
|
## CALLCODE, 0xf2, Message-call into this account with an alternative account's code.
|
||||||
## DELEGATECALL, 0xf4, Message-call into this account with an alternative account's code, but persisting the current values for sender and value.
|
## DELEGATECALL, 0xf4, Message-call into this account with an alternative account's code, but persisting the current values for sender and value.
|
||||||
## STATICCALL, 0xfa, Static message-call into an account.
|
## STATICCALL, 0xfa, Static message-call into an account.
|
||||||
var childComp = `callName Setup`(computation, callName.astToStr)
|
var child = `callName Setup`(c, callName.astToStr)
|
||||||
|
|
||||||
continuation(childComp):
|
continuation(child):
|
||||||
addChildComputation(computation, childComp)
|
addChildComputation(c, child)
|
||||||
|
|
||||||
if childComp.isError:
|
if child.isError:
|
||||||
push: 0
|
push: 0
|
||||||
else:
|
else:
|
||||||
push: 1
|
push: 1
|
||||||
|
|
||||||
if not childComp.shouldEraseReturnData:
|
if not child.shouldEraseReturnData:
|
||||||
let actualOutputSize = min(computation.memOutLen, childComp.output.len)
|
let actualOutputSize = min(c.memOutLen, child.output.len)
|
||||||
computation.memory.write(
|
c.memory.write(
|
||||||
computation.memOutPos,
|
c.memOutPos,
|
||||||
childComp.output.toOpenArray(0, actualOutputSize - 1))
|
child.output.toOpenArray(0, actualOutputSize - 1))
|
||||||
|
|
||||||
when opCode == Call:
|
when opCode == Call:
|
||||||
if emvcStatic == computation.msg.flags and childComp.msg.value > 0.u256:
|
if emvcStatic == c.msg.flags and child.msg.value > 0.u256:
|
||||||
raise newException(StaticContextError, "Cannot modify state while inside of a STATICCALL context")
|
raise newException(StaticContextError, "Cannot modify state while inside of a STATICCALL context")
|
||||||
|
|
||||||
childComp.applyMessage(opCode)
|
child.applyMessage(opCode)
|
||||||
|
|
||||||
genCall(call, Call)
|
genCall(call, Call)
|
||||||
genCall(callCode, CallCode)
|
genCall(callCode, CallCode)
|
||||||
@ -803,35 +797,35 @@ op returnOp, inline = false, startPos, size:
|
|||||||
## 0xf3, Halt execution returning output data.
|
## 0xf3, Halt execution returning output data.
|
||||||
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
|
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[Return].m_handler(computation.memory.len, pos, len),
|
c.gasCosts[Return].m_handler(c.memory.len, pos, len),
|
||||||
reason = "RETURN"
|
reason = "RETURN"
|
||||||
)
|
)
|
||||||
|
|
||||||
computation.memory.extend(pos, len)
|
c.memory.extend(pos, len)
|
||||||
computation.output = computation.memory.read(pos, len)
|
c.output = c.memory.read(pos, len)
|
||||||
|
|
||||||
op revert, inline = false, startPos, size:
|
op revert, inline = false, startPos, size:
|
||||||
## 0xfd, Halt execution reverting state changes but returning data and remaining gas.
|
## 0xfd, Halt execution reverting state changes but returning data and remaining gas.
|
||||||
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
|
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
computation.gasCosts[Revert].m_handler(computation.memory.len, pos, len),
|
c.gasCosts[Revert].m_handler(c.memory.len, pos, len),
|
||||||
reason = "REVERT"
|
reason = "REVERT"
|
||||||
)
|
)
|
||||||
|
|
||||||
computation.memory.extend(pos, len)
|
c.memory.extend(pos, len)
|
||||||
computation.output = computation.memory.read(pos, len)
|
c.output = c.memory.read(pos, len)
|
||||||
# setError(msg, false) will signal cheap revert
|
# setError(msg, false) will signal cheap revert
|
||||||
computation.setError("REVERT opcode executed", false)
|
c.setError("REVERT opcode executed", false)
|
||||||
|
|
||||||
proc selfDestructImpl(computation: BaseComputation, beneficiary: EthAddress) =
|
proc selfDestructImpl(c: Computation, beneficiary: EthAddress) =
|
||||||
## 0xff Halt execution and register account for later deletion.
|
## 0xff Halt execution and register account for later deletion.
|
||||||
# TODO: This is the basic implementation of the self destruct op,
|
# TODO: This is the basic implementation of the self destruct op,
|
||||||
# Other forks have some extra functionality around this call.
|
# Other forks have some extra functionality around this call.
|
||||||
# In particular, EIP150 and EIP161 have extra requirements.
|
# In particular, EIP150 and EIP161 have extra requirements.
|
||||||
computation.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
let
|
let
|
||||||
localBalance = db.getBalance(computation.msg.contractAddress)
|
localBalance = db.getBalance(c.msg.contractAddress)
|
||||||
beneficiaryBalance = db.getBalance(beneficiary)
|
beneficiaryBalance = db.getBalance(beneficiary)
|
||||||
|
|
||||||
# Transfer to beneficiary
|
# Transfer to beneficiary
|
||||||
@ -840,47 +834,47 @@ proc selfDestructImpl(computation: BaseComputation, beneficiary: EthAddress) =
|
|||||||
# Zero the balance of the address being deleted.
|
# Zero the balance of the address being deleted.
|
||||||
# This must come after sending to beneficiary in case the
|
# This must come after sending to beneficiary in case the
|
||||||
# contract named itself as the beneficiary.
|
# contract named itself as the beneficiary.
|
||||||
db.setBalance(computation.msg.contractAddress, 0.u256)
|
db.setBalance(c.msg.contractAddress, 0.u256)
|
||||||
|
|
||||||
# Register the account to be deleted
|
# Register the account to be deleted
|
||||||
computation.registerAccountForDeletion(beneficiary)
|
c.registerAccountForDeletion(beneficiary)
|
||||||
|
|
||||||
trace "SELFDESTRUCT",
|
trace "SELFDESTRUCT",
|
||||||
contractAddress = computation.msg.contractAddress.toHex,
|
contractAddress = c.msg.contractAddress.toHex,
|
||||||
localBalance = localBalance.toString,
|
localBalance = localBalance.toString,
|
||||||
beneficiary = beneficiary.toHex
|
beneficiary = beneficiary.toHex
|
||||||
|
|
||||||
op selfDestruct, inline = false:
|
op selfDestruct, inline = false:
|
||||||
let beneficiary = computation.stack.popAddress()
|
let beneficiary = c.stack.popAddress()
|
||||||
selfDestructImpl(computation, beneficiary)
|
selfDestructImpl(c, beneficiary)
|
||||||
|
|
||||||
op selfDestructEip150, inline = false:
|
op selfDestructEip150, inline = false:
|
||||||
let beneficiary = computation.stack.popAddress()
|
let beneficiary = c.stack.popAddress()
|
||||||
|
|
||||||
let gasParams = GasParams(kind: SelfDestruct,
|
let gasParams = GasParams(kind: SelfDestruct,
|
||||||
sd_condition: not computation.vmState.readOnlyStateDb.accountExists(beneficiary)
|
sd_condition: not c.vmState.readOnlyStateDb.accountExists(beneficiary)
|
||||||
)
|
)
|
||||||
|
|
||||||
let gasCost = computation.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
let gasCost = c.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
||||||
computation.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP150")
|
c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP150")
|
||||||
selfDestructImpl(computation, beneficiary)
|
selfDestructImpl(c, beneficiary)
|
||||||
|
|
||||||
op selfDestructEip161, inline = false:
|
op selfDestructEip161, inline = false:
|
||||||
checkInStaticContext(computation)
|
checkInStaticContext(c)
|
||||||
|
|
||||||
let
|
let
|
||||||
beneficiary = computation.stack.popAddress()
|
beneficiary = c.stack.popAddress()
|
||||||
stateDb = computation.vmState.readOnlyStateDb
|
stateDb = c.vmState.readOnlyStateDb
|
||||||
isDead = stateDb.isDeadAccount(beneficiary)
|
isDead = stateDb.isDeadAccount(beneficiary)
|
||||||
balance = stateDb.getBalance(computation.msg.contractAddress)
|
balance = stateDb.getBalance(c.msg.contractAddress)
|
||||||
|
|
||||||
let gasParams = GasParams(kind: SelfDestruct,
|
let gasParams = GasParams(kind: SelfDestruct,
|
||||||
sd_condition: isDead and not balance.isZero
|
sd_condition: isDead and not balance.isZero
|
||||||
)
|
)
|
||||||
|
|
||||||
let gasCost = computation.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
let gasCost = c.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
||||||
computation.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161")
|
c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161")
|
||||||
selfDestructImpl(computation, beneficiary)
|
selfDestructImpl(c, beneficiary)
|
||||||
|
|
||||||
# Constantinople's new opcodes
|
# Constantinople's new opcodes
|
||||||
op shlOp, inline = true, shift, num:
|
op shlOp, inline = true, shift, num:
|
||||||
@ -899,8 +893,8 @@ op shrOp, inline = true, shift, num:
|
|||||||
push: num shr shiftLen
|
push: num shr shiftLen
|
||||||
|
|
||||||
op sarOp, inline = true:
|
op sarOp, inline = true:
|
||||||
let shiftLen = computation.stack.popInt().safeInt
|
let shiftLen = c.stack.popInt().safeInt
|
||||||
let num = cast[Int256](computation.stack.popInt())
|
let num = cast[Int256](c.stack.popInt())
|
||||||
if shiftLen >= 256:
|
if shiftLen >= 256:
|
||||||
if num.isNegative:
|
if num.isNegative:
|
||||||
push: cast[Uint256]((-1).i256)
|
push: cast[Uint256]((-1).i256)
|
||||||
@ -912,41 +906,41 @@ op sarOp, inline = true:
|
|||||||
push: cast[Uint256](num shr shiftLen)
|
push: cast[Uint256](num shr shiftLen)
|
||||||
|
|
||||||
op extCodeHash, inline = true:
|
op extCodeHash, inline = true:
|
||||||
let address = computation.stack.popAddress()
|
let address = c.stack.popAddress()
|
||||||
# this is very inefficient, it calls underlying
|
# this is very inefficient, it calls underlying
|
||||||
# database too much, we can reduce it by implementing accounts
|
# database too much, we can reduce it by implementing accounts
|
||||||
# cache
|
# cache
|
||||||
if not computation.vmState.readOnlyStateDB.accountExists(address):
|
if not c.vmState.readOnlyStateDB.accountExists(address):
|
||||||
push: 0
|
push: 0
|
||||||
return
|
return
|
||||||
|
|
||||||
if computation.vmState.readOnlyStateDB.isEmptyAccount(address):
|
if c.vmState.readOnlyStateDB.isEmptyAccount(address):
|
||||||
push: 0
|
push: 0
|
||||||
else:
|
else:
|
||||||
push: computation.vmState.readOnlyStateDB.getCodeHash(address)
|
push: c.vmState.readOnlyStateDB.getCodeHash(address)
|
||||||
|
|
||||||
op sstoreEIP2200, inline = false, slot, value:
|
op sstoreEIP2200, inline = false, slot, value:
|
||||||
checkInStaticContext(computation)
|
checkInStaticContext(c)
|
||||||
const SentryGasEIP2200 = 2300 # Minimum gas required to be present for an SSTORE call, not consumed
|
const SentryGasEIP2200 = 2300 # Minimum gas required to be present for an SSTORE call, not consumed
|
||||||
|
|
||||||
if computation.gasMeter.gasRemaining <= SentryGasEIP2200:
|
if c.gasMeter.gasRemaining <= SentryGasEIP2200:
|
||||||
raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE")
|
raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE")
|
||||||
|
|
||||||
let stateDB = computation.vmState.readOnlyStateDB
|
let stateDB = c.vmState.readOnlyStateDB
|
||||||
let (currentValue, existing) = stateDB.getStorage(computation.msg.contractAddress, slot)
|
let (currentValue, existing) = stateDB.getStorage(c.msg.contractAddress, slot)
|
||||||
|
|
||||||
let
|
let
|
||||||
gasParam = GasParams(kind: Op.Sstore,
|
gasParam = GasParams(kind: Op.Sstore,
|
||||||
s_isStorageEmpty: currentValue.isZero,
|
s_isStorageEmpty: currentValue.isZero,
|
||||||
s_currentValue: currentValue,
|
s_currentValue: currentValue,
|
||||||
s_originalValue: stateDB.getCommittedStorage(computation.msg.contractAddress, slot)
|
s_originalValue: stateDB.getCommittedStorage(c.msg.contractAddress, slot)
|
||||||
)
|
)
|
||||||
(gasCost, gasRefund) = computation.gasCosts[Sstore].c_handler(value, gasParam)
|
(gasCost, gasRefund) = c.gasCosts[Sstore].c_handler(value, gasParam)
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(gasCost, &"SSTORE EIP2200: {computation.msg.contractAddress}[{slot}] -> {value} ({currentValue})")
|
c.gasMeter.consumeGas(gasCost, &"SSTORE EIP2200: {c.msg.contractAddress}[{slot}] -> {value} ({currentValue})")
|
||||||
|
|
||||||
if gasRefund != 0:
|
if gasRefund != 0:
|
||||||
computation.gasMeter.refundGas(gasRefund)
|
c.gasMeter.refundGas(gasRefund)
|
||||||
|
|
||||||
computation.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
db.setStorage(computation.msg.contractAddress, slot, value)
|
db.setStorage(c.msg.contractAddress, slot, value)
|
||||||
|
@ -31,7 +31,7 @@ macro op*(procname: untyped, inline: static[bool], stackParams_body: varargs[unt
|
|||||||
# we can't have a nicer macro signature `stackParams: varargs[untyped], body: untyped`
|
# we can't have a nicer macro signature `stackParams: varargs[untyped], body: untyped`
|
||||||
# see https://github.com/nim-lang/Nim/issues/5855 and are forced to "pop"
|
# see https://github.com/nim-lang/Nim/issues/5855 and are forced to "pop"
|
||||||
|
|
||||||
let computation = newIdentNode("computation")
|
let computation = newIdentNode("c")
|
||||||
var stackParams = stackParams_body
|
var stackParams = stackParams_body
|
||||||
|
|
||||||
# 1. Separate stackParams and body with pop
|
# 1. Separate stackParams and body with pop
|
||||||
@ -59,12 +59,12 @@ macro op*(procname: untyped, inline: static[bool], stackParams_body: varargs[unt
|
|||||||
# TODO: replace by func to ensure no side effects
|
# TODO: replace by func to ensure no side effects
|
||||||
if inline:
|
if inline:
|
||||||
result = quote do:
|
result = quote do:
|
||||||
proc `procname`*(`computation`: BaseComputation) {.inline.} =
|
proc `procname`*(`computation`: Computation) {.inline.} =
|
||||||
`popStackStmt`
|
`popStackStmt`
|
||||||
`body`
|
`body`
|
||||||
else:
|
else:
|
||||||
result = quote do:
|
result = quote do:
|
||||||
proc `procname`*(`computation`: BaseComputation) {.gcsafe.} =
|
proc `procname`*(`computation`: Computation) {.gcsafe.} =
|
||||||
`popStackStmt`
|
`popStackStmt`
|
||||||
`body`
|
`body`
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ macro genPush*(): untyped =
|
|||||||
for size in 1 .. 32:
|
for size in 1 .. 32:
|
||||||
let name = genName(size)
|
let name = genName(size)
|
||||||
result.add quote do:
|
result.add quote do:
|
||||||
func `name`*(computation: BaseComputation) {.inline.}=
|
func `name`*(computation: Computation) {.inline.}=
|
||||||
## Push `size`-byte(s) on the stack
|
## Push `size`-byte(s) on the stack
|
||||||
computation.stack.push computation.code.readVmWord(`size`)
|
computation.stack.push computation.code.readVmWord(`size`)
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ macro genDup*(): untyped =
|
|||||||
for pos in 1 .. 16:
|
for pos in 1 .. 16:
|
||||||
let name = genName(pos)
|
let name = genName(pos)
|
||||||
result.add quote do:
|
result.add quote do:
|
||||||
func `name`*(computation: BaseComputation) {.inline.}=
|
func `name`*(computation: Computation) {.inline.}=
|
||||||
computation.stack.dup(`pos`)
|
computation.stack.dup(`pos`)
|
||||||
|
|
||||||
macro genSwap*(): untyped =
|
macro genSwap*(): untyped =
|
||||||
@ -97,16 +97,16 @@ macro genSwap*(): untyped =
|
|||||||
for pos in 1 .. 16:
|
for pos in 1 .. 16:
|
||||||
let name = genName(pos)
|
let name = genName(pos)
|
||||||
result.add quote do:
|
result.add quote do:
|
||||||
func `name`*(computation: BaseComputation) {.inline.}=
|
func `name`*(computation: Computation) {.inline.}=
|
||||||
computation.stack.swap(`pos`)
|
computation.stack.swap(`pos`)
|
||||||
|
|
||||||
template checkInStaticContext*(comp: BaseComputation) =
|
template checkInStaticContext*(comp: Computation) =
|
||||||
# TODO: if possible, this check only appear
|
# TODO: if possible, this check only appear
|
||||||
# when fork >= FkByzantium
|
# when fork >= FkByzantium
|
||||||
if emvcStatic == comp.msg.flags:
|
if emvcStatic == comp.msg.flags:
|
||||||
raise newException(StaticContextError, "Cannot modify state while inside of a STATICCALL context")
|
raise newException(StaticContextError, "Cannot modify state while inside of a STATICCALL context")
|
||||||
|
|
||||||
proc logImpl(c: BaseComputation, opcode: Op, topicCount: int) =
|
proc logImpl(c: Computation, opcode: Op, topicCount: int) =
|
||||||
doAssert(topicCount in 0 .. 4)
|
doAssert(topicCount in 0 .. 4)
|
||||||
checkInStaticContext(c)
|
checkInStaticContext(c)
|
||||||
let (memStartPosition, size) = c.stack.popInt(2)
|
let (memStartPosition, size) = c.stack.popInt(2)
|
||||||
@ -129,8 +129,8 @@ proc logImpl(c: BaseComputation, opcode: Op, topicCount: int) =
|
|||||||
c.addLogEntry(log)
|
c.addLogEntry(log)
|
||||||
|
|
||||||
template genLog*() =
|
template genLog*() =
|
||||||
proc log0*(c: BaseComputation) {.inline.} = logImpl(c, Log0, 0)
|
proc log0*(c: Computation) {.inline.} = logImpl(c, Log0, 0)
|
||||||
proc log1*(c: BaseComputation) {.inline.} = logImpl(c, Log1, 1)
|
proc log1*(c: Computation) {.inline.} = logImpl(c, Log1, 1)
|
||||||
proc log2*(c: BaseComputation) {.inline.} = logImpl(c, Log2, 2)
|
proc log2*(c: Computation) {.inline.} = logImpl(c, Log2, 2)
|
||||||
proc log3*(c: BaseComputation) {.inline.} = logImpl(c, Log3, 3)
|
proc log3*(c: Computation) {.inline.} = logImpl(c, Log3, 3)
|
||||||
proc log4*(c: BaseComputation) {.inline.} = logImpl(c, Log4, 4)
|
proc log4*(c: Computation) {.inline.} = logImpl(c, Log4, 4)
|
||||||
|
@ -16,7 +16,7 @@ import
|
|||||||
logScope:
|
logScope:
|
||||||
topics = "vm opcode"
|
topics = "vm opcode"
|
||||||
|
|
||||||
func invalidInstruction*(computation: BaseComputation) {.inline.} =
|
func invalidInstruction*(c: Computation) {.inline.} =
|
||||||
raise newException(InvalidInstruction, "Invalid instruction, received an opcode not implemented in the current fork.")
|
raise newException(InvalidInstruction, "Invalid instruction, received an opcode not implemented in the current fork.")
|
||||||
|
|
||||||
let FrontierOpDispatch {.compileTime.}: array[Op, NimNode] = block:
|
let FrontierOpDispatch {.compileTime.}: array[Op, NimNode] = block:
|
||||||
@ -223,9 +223,9 @@ proc genIstanbulJumpTable(ops: array[Op, NimNode]): array[Op, NimNode] {.compile
|
|||||||
|
|
||||||
let IstanbulOpDispatch {.compileTime.}: array[Op, NimNode] = genIstanbulJumpTable(ConstantinopleOpDispatch)
|
let IstanbulOpDispatch {.compileTime.}: array[Op, NimNode] = genIstanbulJumpTable(ConstantinopleOpDispatch)
|
||||||
|
|
||||||
proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNode =
|
proc opTableToCaseStmt(opTable: array[Op, NimNode], c: NimNode): NimNode =
|
||||||
|
|
||||||
let instr = quote do: `computation`.instr
|
let instr = quote do: `c`.instr
|
||||||
result = nnkCaseStmt.newTree(instr)
|
result = nnkCaseStmt.newTree(instr)
|
||||||
|
|
||||||
# Add a branch for each (opcode, proc) pair
|
# Add a branch for each (opcode, proc) pair
|
||||||
@ -236,27 +236,27 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo
|
|||||||
if op == Stop:
|
if op == Stop:
|
||||||
quote do:
|
quote do:
|
||||||
trace "op: Stop"
|
trace "op: Stop"
|
||||||
if not `computation`.code.atEnd() and `computation`.tracingEnabled:
|
if not `c`.code.atEnd() and `c`.tracingEnabled:
|
||||||
# we only trace `REAL STOP` and ignore `FAKE STOP`
|
# we only trace `REAL STOP` and ignore `FAKE STOP`
|
||||||
`computation`.opIndex = `computation`.traceOpCodeStarted(`asOp`)
|
`c`.opIndex = `c`.traceOpCodeStarted(`asOp`)
|
||||||
`computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex)
|
`c`.traceOpCodeEnded(`asOp`, `c`.opIndex)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if BaseGasCosts[op].kind == GckFixed:
|
if BaseGasCosts[op].kind == GckFixed:
|
||||||
quote do:
|
quote do:
|
||||||
if `computation`.tracingEnabled:
|
if `c`.tracingEnabled:
|
||||||
`computation`.opIndex = `computation`.traceOpCodeStarted(`asOp`)
|
`c`.opIndex = `c`.traceOpCodeStarted(`asOp`)
|
||||||
`computation`.gasMeter.consumeGas(`computation`.gasCosts[`asOp`].cost, reason = $`asOp`)
|
`c`.gasMeter.consumeGas(`c`.gasCosts[`asOp`].cost, reason = $`asOp`)
|
||||||
`opImpl`(`computation`)
|
`opImpl`(`c`)
|
||||||
if `computation`.tracingEnabled:
|
if `c`.tracingEnabled:
|
||||||
`computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex)
|
`c`.traceOpCodeEnded(`asOp`, `c`.opIndex)
|
||||||
else:
|
else:
|
||||||
quote do:
|
quote do:
|
||||||
if `computation`.tracingEnabled:
|
if `c`.tracingEnabled:
|
||||||
`computation`.opIndex = `computation`.traceOpCodeStarted(`asOp`)
|
`c`.opIndex = `c`.traceOpCodeStarted(`asOp`)
|
||||||
`opImpl`(`computation`)
|
`opImpl`(`c`)
|
||||||
if `computation`.tracingEnabled:
|
if `c`.tracingEnabled:
|
||||||
`computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex)
|
`c`.traceOpCodeEnded(`asOp`, `c`.opIndex)
|
||||||
when `asOp` in {Return, Revert, SelfDestruct}:
|
when `asOp` in {Return, Revert, SelfDestruct}:
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -267,90 +267,90 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo
|
|||||||
|
|
||||||
# Wrap the case statement in while true + computed goto
|
# Wrap the case statement in while true + computed goto
|
||||||
result = quote do:
|
result = quote do:
|
||||||
if `computation`.tracingEnabled:
|
if `c`.tracingEnabled:
|
||||||
`computation`.prepareTracer()
|
`c`.prepareTracer()
|
||||||
while true:
|
while true:
|
||||||
`instr` = `computation`.code.next()
|
`instr` = `c`.code.next()
|
||||||
#{.computedGoto.}
|
#{.computedGoto.}
|
||||||
# computed goto causing stack overflow, it consumes a lot of space
|
# computed goto causing stack overflow, it consumes a lot of space
|
||||||
# we could use manual jump table instead
|
# we could use manual jump table instead
|
||||||
# TODO lots of macro magic here to unravel, with chronicles...
|
# TODO lots of macro magic here to unravel, with chronicles...
|
||||||
# `computation`.logger.log($`computation`.stack & "\n\n", fgGreen)
|
# `c`.logger.log($`c`.stack & "\n\n", fgGreen)
|
||||||
`result`
|
`result`
|
||||||
|
|
||||||
macro genFrontierDispatch(computation: BaseComputation): untyped =
|
macro genFrontierDispatch(c: Computation): untyped =
|
||||||
result = opTableToCaseStmt(FrontierOpDispatch, computation)
|
result = opTableToCaseStmt(FrontierOpDispatch, c)
|
||||||
|
|
||||||
macro genHomesteadDispatch(computation: BaseComputation): untyped =
|
macro genHomesteadDispatch(c: Computation): untyped =
|
||||||
result = opTableToCaseStmt(HomesteadOpDispatch, computation)
|
result = opTableToCaseStmt(HomesteadOpDispatch, c)
|
||||||
|
|
||||||
macro genTangerineDispatch(computation: BaseComputation): untyped =
|
macro genTangerineDispatch(c: Computation): untyped =
|
||||||
result = opTableToCaseStmt(TangerineOpDispatch, computation)
|
result = opTableToCaseStmt(TangerineOpDispatch, c)
|
||||||
|
|
||||||
macro genSpuriousDispatch(computation: BaseComputation): untyped =
|
macro genSpuriousDispatch(c: Computation): untyped =
|
||||||
result = opTableToCaseStmt(SpuriousOpDispatch, computation)
|
result = opTableToCaseStmt(SpuriousOpDispatch, c)
|
||||||
|
|
||||||
macro genByzantiumDispatch(computation: BaseComputation): untyped =
|
macro genByzantiumDispatch(c: Computation): untyped =
|
||||||
result = opTableToCaseStmt(ByzantiumOpDispatch, computation)
|
result = opTableToCaseStmt(ByzantiumOpDispatch, c)
|
||||||
|
|
||||||
macro genConstantinopleDispatch(computation: BaseComputation): untyped =
|
macro genConstantinopleDispatch(c: Computation): untyped =
|
||||||
result = opTableToCaseStmt(ConstantinopleOpDispatch, computation)
|
result = opTableToCaseStmt(ConstantinopleOpDispatch, c)
|
||||||
|
|
||||||
macro genIstanbulDispatch(computation: BaseComputation): untyped =
|
macro genIstanbulDispatch(c: Computation): untyped =
|
||||||
result = opTableToCaseStmt(IstanbulOpDispatch, computation)
|
result = opTableToCaseStmt(IstanbulOpDispatch, c)
|
||||||
|
|
||||||
proc frontierVM(computation: BaseComputation) =
|
proc frontierVM(c: Computation) =
|
||||||
genFrontierDispatch(computation)
|
genFrontierDispatch(c)
|
||||||
|
|
||||||
proc homesteadVM(computation: BaseComputation) =
|
proc homesteadVM(c: Computation) =
|
||||||
genHomesteadDispatch(computation)
|
genHomesteadDispatch(c)
|
||||||
|
|
||||||
proc tangerineVM(computation: BaseComputation) =
|
proc tangerineVM(c: Computation) =
|
||||||
genTangerineDispatch(computation)
|
genTangerineDispatch(c)
|
||||||
|
|
||||||
proc spuriousVM(computation: BaseComputation) {.gcsafe.} =
|
proc spuriousVM(c: Computation) {.gcsafe.} =
|
||||||
genSpuriousDispatch(computation)
|
genSpuriousDispatch(c)
|
||||||
|
|
||||||
proc byzantiumVM(computation: BaseComputation) {.gcsafe.} =
|
proc byzantiumVM(c: Computation) {.gcsafe.} =
|
||||||
genByzantiumDispatch(computation)
|
genByzantiumDispatch(c)
|
||||||
|
|
||||||
proc constantinopleVM(computation: BaseComputation) {.gcsafe.} =
|
proc constantinopleVM(c: Computation) {.gcsafe.} =
|
||||||
genConstantinopleDispatch(computation)
|
genConstantinopleDispatch(c)
|
||||||
|
|
||||||
proc istanbulVM(computation: BaseComputation) {.gcsafe.} =
|
proc istanbulVM(c: Computation) {.gcsafe.} =
|
||||||
genIstanbulDispatch(computation)
|
genIstanbulDispatch(c)
|
||||||
|
|
||||||
proc selectVM(computation: BaseComputation, fork: Fork) {.gcsafe.} =
|
proc selectVM(c: Computation, fork: Fork) {.gcsafe.} =
|
||||||
# TODO: Optimise getting fork and updating opCodeExec only when necessary
|
# TODO: Optimise getting fork and updating opCodeExec only when necessary
|
||||||
case fork
|
case fork
|
||||||
of FkFrontier..FkThawing:
|
of FkFrontier..FkThawing:
|
||||||
computation.frontierVM()
|
c.frontierVM()
|
||||||
of FkHomestead..FkDao:
|
of FkHomestead..FkDao:
|
||||||
computation.homesteadVM()
|
c.homesteadVM()
|
||||||
of FkTangerine:
|
of FkTangerine:
|
||||||
computation.tangerineVM()
|
c.tangerineVM()
|
||||||
of FkSpurious:
|
of FkSpurious:
|
||||||
computation.spuriousVM()
|
c.spuriousVM()
|
||||||
of FkByzantium:
|
of FkByzantium:
|
||||||
computation.byzantiumVM()
|
c.byzantiumVM()
|
||||||
of FkConstantinople:
|
of FkConstantinople:
|
||||||
computation.constantinopleVM()
|
c.constantinopleVM()
|
||||||
else:
|
else:
|
||||||
computation.istanbulVM()
|
c.istanbulVM()
|
||||||
|
|
||||||
proc executeOpcodes(computation: BaseComputation) =
|
proc executeOpcodes(c: Computation) =
|
||||||
let fork = computation.fork
|
let fork = c.fork
|
||||||
|
|
||||||
block:
|
block:
|
||||||
if computation.execPrecompiles(fork):
|
if c.execPrecompiles(fork):
|
||||||
break
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
computation.selectVM(fork)
|
c.selectVM(fork)
|
||||||
except CatchableError as e:
|
except CatchableError as e:
|
||||||
computation.setError(&"Opcode Dispatch Error msg={e.msg}, depth={computation.msg.depth}", true)
|
c.setError(&"Opcode Dispatch Error msg={e.msg}, depth={c.msg.depth}", true)
|
||||||
|
|
||||||
computation.nextProc()
|
c.nextProc()
|
||||||
if computation.isError():
|
if c.isError():
|
||||||
if computation.tracingEnabled: computation.traceError()
|
if c.tracingEnabled: c.traceError()
|
||||||
debug "executeOpcodes error", msg=computation.error.info
|
debug "executeOpcodes error", msg=c.error.info
|
||||||
|
@ -18,7 +18,7 @@ type
|
|||||||
# Istanbul
|
# Istanbul
|
||||||
paBlake2bf = 9
|
paBlake2bf = 9
|
||||||
|
|
||||||
proc getSignature(computation: BaseComputation): (array[32, byte], Signature) =
|
proc getSignature(computation: Computation): (array[32, byte], Signature) =
|
||||||
# input is Hash, V, R, S
|
# input is Hash, V, R, S
|
||||||
template data: untyped = computation.msg.data
|
template data: untyped = computation.msg.data
|
||||||
var bytes: array[65, byte] # will hold R[32], S[32], V[1], in that order
|
var bytes: array[65, byte] # will hold R[32], S[32], V[1], in that order
|
||||||
@ -91,7 +91,7 @@ proc getFR(data: openarray[byte]): FR =
|
|||||||
if not result.fromBytes2(data):
|
if not result.fromBytes2(data):
|
||||||
raise newException(ValidationError, "Could not get FR value")
|
raise newException(ValidationError, "Could not get FR value")
|
||||||
|
|
||||||
proc ecRecover*(computation: BaseComputation) =
|
proc ecRecover*(computation: Computation) =
|
||||||
computation.gasMeter.consumeGas(
|
computation.gasMeter.consumeGas(
|
||||||
GasECRecover,
|
GasECRecover,
|
||||||
reason="ECRecover Precompile")
|
reason="ECRecover Precompile")
|
||||||
@ -107,7 +107,7 @@ proc ecRecover*(computation: BaseComputation) =
|
|||||||
computation.rawOutput[12..31] = pubKey.toCanonicalAddress()
|
computation.rawOutput[12..31] = pubKey.toCanonicalAddress()
|
||||||
trace "ECRecover precompile", derivedKey = pubKey.toCanonicalAddress()
|
trace "ECRecover precompile", derivedKey = pubKey.toCanonicalAddress()
|
||||||
|
|
||||||
proc sha256*(computation: BaseComputation) =
|
proc sha256*(computation: Computation) =
|
||||||
let
|
let
|
||||||
wordCount = wordCount(computation.msg.data.len)
|
wordCount = wordCount(computation.msg.data.len)
|
||||||
gasFee = GasSHA256 + wordCount * GasSHA256Word
|
gasFee = GasSHA256 + wordCount * GasSHA256Word
|
||||||
@ -116,7 +116,7 @@ proc sha256*(computation: BaseComputation) =
|
|||||||
computation.rawOutput = @(nimcrypto.sha_256.digest(computation.msg.data).data)
|
computation.rawOutput = @(nimcrypto.sha_256.digest(computation.msg.data).data)
|
||||||
trace "SHA256 precompile", output = computation.rawOutput.toHex
|
trace "SHA256 precompile", output = computation.rawOutput.toHex
|
||||||
|
|
||||||
proc ripemd160*(computation: BaseComputation) =
|
proc ripemd160*(computation: Computation) =
|
||||||
let
|
let
|
||||||
wordCount = wordCount(computation.msg.data.len)
|
wordCount = wordCount(computation.msg.data.len)
|
||||||
gasFee = GasRIPEMD160 + wordCount * GasRIPEMD160Word
|
gasFee = GasRIPEMD160 + wordCount * GasRIPEMD160Word
|
||||||
@ -126,7 +126,7 @@ proc ripemd160*(computation: BaseComputation) =
|
|||||||
computation.rawOutput[12..31] = @(nimcrypto.ripemd160.digest(computation.msg.data).data)
|
computation.rawOutput[12..31] = @(nimcrypto.ripemd160.digest(computation.msg.data).data)
|
||||||
trace "RIPEMD160 precompile", output = computation.rawOutput.toHex
|
trace "RIPEMD160 precompile", output = computation.rawOutput.toHex
|
||||||
|
|
||||||
proc identity*(computation: BaseComputation) =
|
proc identity*(computation: Computation) =
|
||||||
let
|
let
|
||||||
wordCount = wordCount(computation.msg.data.len)
|
wordCount = wordCount(computation.msg.data.len)
|
||||||
gasFee = GasIdentity + wordCount * GasIdentityWord
|
gasFee = GasIdentity + wordCount * GasIdentityWord
|
||||||
@ -135,7 +135,7 @@ proc identity*(computation: BaseComputation) =
|
|||||||
computation.rawOutput = computation.msg.data
|
computation.rawOutput = computation.msg.data
|
||||||
trace "Identity precompile", output = computation.rawOutput.toHex
|
trace "Identity precompile", output = computation.rawOutput.toHex
|
||||||
|
|
||||||
proc modExpInternal(computation: BaseComputation, base_len, exp_len, mod_len: int, T: type StUint) =
|
proc modExpInternal(computation: Computation, base_len, exp_len, mod_len: int, T: type StUint) =
|
||||||
template rawMsg: untyped {.dirty.} =
|
template rawMsg: untyped {.dirty.} =
|
||||||
computation.msg.data
|
computation.msg.data
|
||||||
|
|
||||||
@ -208,7 +208,7 @@ proc modExpInternal(computation: BaseComputation, base_len, exp_len, mod_len: in
|
|||||||
computation.rawOutput = newSeq[byte](mod_len)
|
computation.rawOutput = newSeq[byte](mod_len)
|
||||||
computation.rawOutput[^output.len..^1] = output[0..^1]
|
computation.rawOutput[^output.len..^1] = output[0..^1]
|
||||||
|
|
||||||
proc modExp*(computation: BaseComputation) =
|
proc modExp*(computation: Computation) =
|
||||||
## Modular exponentiation precompiled contract
|
## Modular exponentiation precompiled contract
|
||||||
## Yellow Paper Appendix E
|
## Yellow Paper Appendix E
|
||||||
## EIP-198 - https://github.com/ethereum/EIPs/blob/master/EIPS/eip-198.md
|
## EIP-198 - https://github.com/ethereum/EIPs/blob/master/EIPS/eip-198.md
|
||||||
@ -237,7 +237,7 @@ proc modExp*(computation: BaseComputation) =
|
|||||||
else:
|
else:
|
||||||
raise newException(EVMError, "The Nimbus VM doesn't support modular exponentiation with numbers larger than uint8192")
|
raise newException(EVMError, "The Nimbus VM doesn't support modular exponentiation with numbers larger than uint8192")
|
||||||
|
|
||||||
proc bn256ecAdd*(computation: BaseComputation, fork: Fork = FkByzantium) =
|
proc bn256ecAdd*(computation: Computation, fork: Fork = FkByzantium) =
|
||||||
let gasFee = if fork < FkIstanbul: GasECAdd else: GasECAddIstanbul
|
let gasFee = if fork < FkIstanbul: GasECAdd else: GasECAddIstanbul
|
||||||
computation.gasMeter.consumeGas(gasFee, reason = "ecAdd Precompile")
|
computation.gasMeter.consumeGas(gasFee, reason = "ecAdd Precompile")
|
||||||
|
|
||||||
@ -258,7 +258,7 @@ proc bn256ecAdd*(computation: BaseComputation, fork: Fork = FkByzantium) =
|
|||||||
|
|
||||||
computation.rawOutput = @output
|
computation.rawOutput = @output
|
||||||
|
|
||||||
proc bn256ecMul*(computation: BaseComputation, fork: Fork = FkByzantium) =
|
proc bn256ecMul*(computation: Computation, fork: Fork = FkByzantium) =
|
||||||
let gasFee = if fork < FkIstanbul: GasECMul else: GasECMulIstanbul
|
let gasFee = if fork < FkIstanbul: GasECMul else: GasECMulIstanbul
|
||||||
computation.gasMeter.consumeGas(gasFee, reason="ecMul Precompile")
|
computation.gasMeter.consumeGas(gasFee, reason="ecMul Precompile")
|
||||||
|
|
||||||
@ -281,7 +281,7 @@ proc bn256ecMul*(computation: BaseComputation, fork: Fork = FkByzantium) =
|
|||||||
|
|
||||||
computation.rawOutput = @output
|
computation.rawOutput = @output
|
||||||
|
|
||||||
proc bn256ecPairing*(computation: BaseComputation, fork: Fork = FkByzantium) =
|
proc bn256ecPairing*(computation: Computation, fork: Fork = FkByzantium) =
|
||||||
let msglen = len(computation.msg.data)
|
let msglen = len(computation.msg.data)
|
||||||
if msglen mod 192 != 0:
|
if msglen mod 192 != 0:
|
||||||
raise newException(ValidationError, "Invalid input length")
|
raise newException(ValidationError, "Invalid input length")
|
||||||
@ -318,7 +318,7 @@ proc bn256ecPairing*(computation: BaseComputation, fork: Fork = FkByzantium) =
|
|||||||
|
|
||||||
computation.rawOutput = @output
|
computation.rawOutput = @output
|
||||||
|
|
||||||
proc blake2bf*(computation: BaseComputation) =
|
proc blake2bf*(computation: Computation) =
|
||||||
template input(): untyped =
|
template input(): untyped =
|
||||||
computation.msg.data
|
computation.msg.data
|
||||||
|
|
||||||
@ -337,7 +337,7 @@ proc getMaxPrecompileAddr(fork: Fork): PrecompileAddresses =
|
|||||||
elif fork < FkIstanbul: paPairing
|
elif fork < FkIstanbul: paPairing
|
||||||
else: PrecompileAddresses.high
|
else: PrecompileAddresses.high
|
||||||
|
|
||||||
proc execPrecompiles*(computation: BaseComputation, fork: Fork): bool {.inline.} =
|
proc execPrecompiles*(computation: Computation, fork: Fork): bool {.inline.} =
|
||||||
for i in 0..18:
|
for i in 0..18:
|
||||||
if computation.msg.codeAddress[i] != 0: return
|
if computation.msg.codeAddress[i] != 0: return
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ iterator storage(tracer: TransactionTracer, compDepth: int): Uint256 =
|
|||||||
for key in tracer.storageKeys[compDepth]:
|
for key in tracer.storageKeys[compDepth]:
|
||||||
yield key
|
yield key
|
||||||
|
|
||||||
proc traceOpCodeStarted*(tracer: var TransactionTracer, c: BaseComputation, op: Op): int =
|
proc traceOpCodeStarted*(tracer: var TransactionTracer, c: Computation, op: Op): int =
|
||||||
if unlikely tracer.trace.isNil:
|
if unlikely tracer.trace.isNil:
|
||||||
tracer.initTracer()
|
tracer.initTracer()
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ proc traceOpCodeStarted*(tracer: var TransactionTracer, c: BaseComputation, op:
|
|||||||
|
|
||||||
result = tracer.trace["structLogs"].len - 1
|
result = tracer.trace["structLogs"].len - 1
|
||||||
|
|
||||||
proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation, op: Op, lastIndex: int) =
|
proc traceOpCodeEnded*(tracer: var TransactionTracer, c: Computation, op: Op, lastIndex: int) =
|
||||||
let j = tracer.trace["structLogs"].elems[lastIndex]
|
let j = tracer.trace["structLogs"].elems[lastIndex]
|
||||||
|
|
||||||
# TODO: figure out how to get storage
|
# TODO: figure out how to get storage
|
||||||
@ -114,7 +114,7 @@ proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation, op: Op
|
|||||||
|
|
||||||
trace "Op", json = j.pretty()
|
trace "Op", json = j.pretty()
|
||||||
|
|
||||||
proc traceError*(tracer: var TransactionTracer, c: BaseComputation) =
|
proc traceError*(tracer: var TransactionTracer, c: Computation) =
|
||||||
if tracer.trace["structLogs"].elems.len > 0:
|
if tracer.trace["structLogs"].elems.len > 0:
|
||||||
let j = tracer.trace["structLogs"].elems[^1]
|
let j = tracer.trace["structLogs"].elems[^1]
|
||||||
j["error"] = %(c.error.info)
|
j["error"] = %(c.error.info)
|
||||||
|
@ -26,7 +26,7 @@ proc validateTransaction*(vmState: BaseVMState, tx: Transaction, sender: EthAddr
|
|||||||
tx.accountNonce == account.nonce and
|
tx.accountNonce == account.nonce and
|
||||||
account.balance >= gasCost
|
account.balance >= gasCost
|
||||||
|
|
||||||
proc setupComputation*(vmState: BaseVMState, tx: Transaction, sender, recipient: EthAddress, fork: Fork) : BaseComputation =
|
proc setupComputation*(vmState: BaseVMState, tx: Transaction, sender, recipient: EthAddress, fork: Fork) : Computation =
|
||||||
var gas = tx.gasLimit - tx.intrinsicGas(fork)
|
var gas = tx.gasLimit - tx.intrinsicGas(fork)
|
||||||
|
|
||||||
# TODO: refactor message to use byterange
|
# TODO: refactor message to use byterange
|
||||||
@ -58,46 +58,46 @@ proc setupComputation*(vmState: BaseVMState, tx: Transaction, sender, recipient:
|
|||||||
code: code
|
code: code
|
||||||
)
|
)
|
||||||
|
|
||||||
result = newBaseComputation(vmState, msg, some(fork))
|
result = newComputation(vmState, msg, some(fork))
|
||||||
doAssert result.isOriginComputation
|
doAssert result.isOriginComputation
|
||||||
|
|
||||||
proc execComputation*(computation: var BaseComputation) =
|
proc execComputation*(c: Computation) =
|
||||||
if computation.msg.isCreate:
|
if c.msg.isCreate:
|
||||||
computation.applyMessage(Create)
|
c.applyMessage(Create)
|
||||||
else:
|
else:
|
||||||
computation.applyMessage(Call)
|
c.applyMessage(Call)
|
||||||
|
|
||||||
computation.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
var suicidedCount = 0
|
var suicidedCount = 0
|
||||||
for deletedAccount in computation.accountsForDeletion:
|
for deletedAccount in c.accountsForDeletion:
|
||||||
db.deleteAccount deletedAccount
|
db.deleteAccount deletedAccount
|
||||||
inc suicidedCount
|
inc suicidedCount
|
||||||
|
|
||||||
# FIXME: hook this into actual RefundSelfDestruct
|
# FIXME: hook this into actual RefundSelfDestruct
|
||||||
const RefundSelfDestruct = 24_000
|
const RefundSelfDestruct = 24_000
|
||||||
computation.gasMeter.refundGas(RefundSelfDestruct * suicidedCount)
|
c.gasMeter.refundGas(RefundSelfDestruct * suicidedCount)
|
||||||
|
|
||||||
if computation.fork >= FkSpurious:
|
if c.fork >= FkSpurious:
|
||||||
computation.collectTouchedAccounts()
|
c.collectTouchedAccounts()
|
||||||
|
|
||||||
computation.vmstate.status = computation.isSuccess
|
c.vmstate.status = c.isSuccess
|
||||||
if computation.isSuccess:
|
if c.isSuccess:
|
||||||
computation.vmState.addLogs(computation.logEntries)
|
c.vmState.addLogs(c.logEntries)
|
||||||
|
|
||||||
proc refundGas*(computation: BaseComputation, tx: Transaction, sender: EthAddress): GasInt =
|
proc refundGas*(c: Computation, tx: Transaction, sender: EthAddress): GasInt =
|
||||||
let
|
let
|
||||||
gasRemaining = computation.gasMeter.gasRemaining
|
gasRemaining = c.gasMeter.gasRemaining
|
||||||
gasRefunded = computation.getGasRefund()
|
gasRefunded = c.getGasRefund()
|
||||||
gasUsed = tx.gasLimit - gasRemaining
|
gasUsed = tx.gasLimit - gasRemaining
|
||||||
gasRefund = min(gasRefunded, gasUsed div 2)
|
gasRefund = min(gasRefunded, gasUsed div 2)
|
||||||
|
|
||||||
computation.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
db.addBalance(sender, (gasRemaining + gasRefund).u256 * tx.gasPrice.u256)
|
db.addBalance(sender, (gasRemaining + gasRefund).u256 * tx.gasPrice.u256)
|
||||||
|
|
||||||
result = gasUsed - gasRefund
|
result = gasUsed - gasRefund
|
||||||
|
|
||||||
#[
|
#[
|
||||||
method executeTransaction(vmState: BaseVMState, transaction: Transaction): (BaseComputation, BlockHeader) {.base.}=
|
method executeTransaction(vmState: BaseVMState, transaction: Transaction): (Computation, BlockHeader) {.base.}=
|
||||||
# Execute the transaction in the vm
|
# Execute the transaction in the vm
|
||||||
# TODO: introduced here: https://github.com/ethereum/py-evm/commit/21c57f2d56ab91bb62723c3f9ebe291d0b132dde
|
# TODO: introduced here: https://github.com/ethereum/py-evm/commit/21c57f2d56ab91bb62723c3f9ebe291d0b132dde
|
||||||
# Refactored/Removed here: https://github.com/ethereum/py-evm/commit/cc991bf
|
# Refactored/Removed here: https://github.com/ethereum/py-evm/commit/cc991bf
|
||||||
@ -105,7 +105,7 @@ method executeTransaction(vmState: BaseVMState, transaction: Transaction): (Base
|
|||||||
raise newException(ValueError, "Must be implemented by subclasses")
|
raise newException(ValueError, "Must be implemented by subclasses")
|
||||||
|
|
||||||
|
|
||||||
method addTransaction*(vmState: BaseVMState, transaction: Transaction, computation: BaseComputation, b: Block): (Block, Table[string, string]) =
|
method addTransaction*(vmState: BaseVMState, transaction: Transaction, c: Computation, b: Block): (Block, Table[string, string]) =
|
||||||
# Add a transaction to the given block and
|
# Add a transaction to the given block and
|
||||||
# return `trieData` to store the transaction data in chaindb in VM layer
|
# return `trieData` to store the transaction data in chaindb in VM layer
|
||||||
# Update the bloomFilter, transaction trie and receipt trie roots, bloom_filter,
|
# Update the bloomFilter, transaction trie and receipt trie roots, bloom_filter,
|
||||||
@ -138,7 +138,7 @@ method applyTransaction*(
|
|||||||
vmState: BaseVMState,
|
vmState: BaseVMState,
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
b: Block,
|
b: Block,
|
||||||
isStateless: bool): (BaseComputation, Block, Table[string, string]) =
|
isStateless: bool): (Computation, Block, Table[string, string]) =
|
||||||
# Apply transaction to the given block
|
# Apply transaction to the given block
|
||||||
# transaction: the transaction need to be applied
|
# transaction: the transaction need to be applied
|
||||||
# b: the block which the transaction applies on
|
# b: the block which the transaction applies on
|
||||||
|
@ -51,7 +51,7 @@ type
|
|||||||
transaction*: DbTransaction
|
transaction*: DbTransaction
|
||||||
intermediateRoot*: Hash256
|
intermediateRoot*: Hash256
|
||||||
|
|
||||||
BaseComputation* = ref object of RootObj
|
Computation* = ref object
|
||||||
# The execution computation
|
# The execution computation
|
||||||
vmState*: BaseVMState
|
vmState*: BaseVMState
|
||||||
msg*: Message
|
msg*: Message
|
||||||
|
@ -194,7 +194,7 @@ proc generateVMProxy(boa: Assembler): NimNode =
|
|||||||
const
|
const
|
||||||
blockFile = "tests" / "fixtures" / "PersistBlockTests" / "block47205.json"
|
blockFile = "tests" / "fixtures" / "PersistBlockTests" / "block47205.json"
|
||||||
|
|
||||||
proc initComputation(vmState: BaseVMState, tx: Transaction, sender: EthAddress, data: seq[byte], forkOverride=none(Fork)) : BaseComputation =
|
proc initComputation(vmState: BaseVMState, tx: Transaction, sender: EthAddress, data: seq[byte], forkOverride=none(Fork)) : Computation =
|
||||||
doAssert tx.isContractCreation
|
doAssert tx.isContractCreation
|
||||||
|
|
||||||
let fork =
|
let fork =
|
||||||
@ -220,7 +220,7 @@ proc initComputation(vmState: BaseVMState, tx: Transaction, sender: EthAddress,
|
|||||||
code: tx.payload
|
code: tx.payload
|
||||||
)
|
)
|
||||||
|
|
||||||
newBaseComputation(vmState, msg, some(fork))
|
newComputation(vmState, msg, some(fork))
|
||||||
|
|
||||||
proc initDatabase*(): (Uint256, BaseChainDB) =
|
proc initDatabase*(): (Uint256, BaseChainDB) =
|
||||||
let
|
let
|
||||||
@ -236,7 +236,7 @@ proc initDatabase*(): (Uint256, BaseChainDB) =
|
|||||||
|
|
||||||
result = (blockNumber, newBaseChainDB(memoryDB, false))
|
result = (blockNumber, newBaseChainDB(memoryDB, false))
|
||||||
|
|
||||||
proc initComputation(blockNumber: Uint256, chainDB: BaseChainDB, payload, data: seq[byte], fork: Fork): BaseComputation =
|
proc initComputation(blockNumber: Uint256, chainDB: BaseChainDB, payload, data: seq[byte], fork: Fork): Computation =
|
||||||
let
|
let
|
||||||
parentNumber = blockNumber - 1
|
parentNumber = blockNumber - 1
|
||||||
parent = chainDB.getBlockHeader(parentNumber)
|
parent = chainDB.getBlockHeader(parentNumber)
|
||||||
|
@ -41,7 +41,7 @@ template doTest(fixture: JsonNode, address: byte, action: untyped): untyped =
|
|||||||
data: data,
|
data: data,
|
||||||
code: @[]
|
code: @[]
|
||||||
)
|
)
|
||||||
computation = newBaseComputation(vmState, message)
|
computation = newComputation(vmState, message)
|
||||||
echo "Running ", action.astToStr, " - ", test["name"]
|
echo "Running ", action.astToStr, " - ", test["name"]
|
||||||
`action`(computation)
|
`action`(computation)
|
||||||
let c = computation.rawOutput == expected
|
let c = computation.rawOutput == expected
|
||||||
|
@ -59,7 +59,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
|||||||
code: code
|
code: code
|
||||||
)
|
)
|
||||||
|
|
||||||
var computation = newBaseComputation(vmState, message)
|
var computation = newComputation(vmState, message)
|
||||||
computation.executeOpcodes()
|
computation.executeOpcodes()
|
||||||
|
|
||||||
if not fixture{"post"}.isNil:
|
if not fixture{"post"}.isNil:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user