diff --git a/src/logic/call.nim b/src/logic/call.nim index 610b900fc..07151329d 100644 --- a/src/logic/call.nim +++ b/src/logic/call.nim @@ -200,7 +200,7 @@ method callParams(call: DelegateCall, computation): (Int256, Int256, cstring, cs false, # should_transfer_value, computation.msg.isStatic) -proc maxChildGasEIP150(gas: Int256): Int256 = +proc maxChildGasEIP150*(gas: Int256): Int256 = gas - gas div 64 proc computeEIP150MsgGas(computation; gas: Int256, extraGas: Int256, value: Int256, name: string, callStipend: Int256): (Int256, Int256) = diff --git a/src/logic/system_ops.nim b/src/logic/system_ops.nim new file mode 100644 index 000000000..e27015eed --- /dev/null +++ b/src/logic/system_ops.nim @@ -0,0 +1,154 @@ +import + strformat, + ../constants, ../errors, ../computation, ../opcode, ../opcode_values, ../logging, ../vm_state, call, + .. / vm / [stack, gas_meter, memory, message], .. / utils / [address, hexadecimal, bytes], + bigints + +{.this: computation.} +{.experimental.} + +using + computation: var BaseComputation + +type + Create* = ref object of Opcode + + CreateEIP150* = ref object of Create + + CreateByzantium* = ref object of CreateEIP150 + +method maxChildGasModifier(create: Create, gas: Int256): Int256 {.base.} = + gas + +method runLogic*(create: Create, computation) = + computation.gasMeter.consumeGas(create.gasCost(computation), reason = $create.kind) + let (value, startPosition, size) = computation.stack.popInt(3) + computation.extendMemory(startPosition, size) + + # TODO: with + # with computation.vm_state.state_db(read_only=True) as state_db: + # insufficient_funds = state_db.get_balance( + # computation.msg.storage_address) < value + # stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT + + # if insufficient_funds or stack_too_deep: + # computation.stack.push(0) + # return + + let callData = computation.memory.read(startPosition, size) + let createMsgGas = create.maxChildGasModifier(computation.gasMeter.gasRemaining) + computation.gasMeter.consumeGas(createMsgGas, reason="CREATE") + + # TODO: with + # with computation.vm_state.state_db() as state_db: + # creation_nonce = state_db.get_nonce(computation.msg.storage_address) + # state_db.increment_nonce(computation.msg.storage_address) + + # contract_address = generate_contract_address( + # computation.msg.storage_address, + # creation_nonce, + # ) + + # is_collision = state_db.account_has_code_or_nonce(contract_address) + let contractAddress = cstring"" + let isCollision = false + + if isCollision: + computation.vmState.logger.debug(&"Address collision while creating contract: {contractAddress.encodeHex}") + computation.stack.push(0.i256) + return + + let childMsg = computation.prepareChildMessage( + gas=createMsgGas, + to=constants.CREATE_CONTRACT_ADDRESS, + value=value, + data=cast[seq[byte]](@[]), + code=callData.toCString, + options=MessageOptions(createAddress: contractAddress)) + + # let childComputation = computation.applyChildComputation(childMsg) + var childComputation: BaseComputation + + if childComputation.isError: + computation.stack.push(0.i256) + else: + computation.stack.push(contractAddress) + computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining) + +method maxChildGasModifier(create: CreateEIP150, gas: Int256): Int256 = + maxChildGasEIP150(gas) + +method runLogic*(create: CreateByzantium, computation) = + if computation.msg.isStatic: + raise newException(WriteProtection, "Cannot modify state while inside of a STATICCALL context") + procCall runLogic(create, computation) + +proc selfdestructEIP150(computation) = + let beneficiary = forceBytesToAddress(stack.popBinary) + # TODO: with + # with computation.vm_state.state_db(read_only=True) as state_db: + # if not state_db.account_exists(beneficiary): + # computation.gas_meter.consume_gas( + # constants.GAS_SELFDESTRUCT_NEWACCOUNT, + # reason=mnemonics.SELFDESTRUCT, + # ) + # _selfdestruct(computation, beneficiary) + +proc selfdestructEIP161(computation) = + let beneficiary = forceBytesToAddress(stack.popBinary) + # TODO: with + # with computation.vm_state.state_db(read_only=True) as state_db: + # is_dead = ( + # not state_db.account_exists(beneficiary) or + # state_db.account_is_empty(beneficiary) + # ) + # if is_dead and state_db.get_balance(computation.msg.storage_address): + # computation.gas_meter.consume_gas( + # constants.GAS_SELFDESTRUCT_NEWACCOUNT, + # reason=mnemonics.SELFDESTRUCT, + # ) + # _selfdestruct(computation, beneficiary) + +proc selfdestruct(computation; beneficiary: cstring) = + discard # TODO: with + # with computation.vm_state.state_db() as state_db: + # local_balance = state_db.get_balance(computation.msg.storage_address) + # beneficiary_balance = state_db.get_balance(beneficiary) + + # # 1st: Transfer to beneficiary + # state_db.set_balance(beneficiary, local_balance + beneficiary_balance) + # # 2nd: Zero the balance of the address being deleted (must come after + # # sending to beneficiary in case the contract named itself as the + # # beneficiary. + # state_db.set_balance(computation.msg.storage_address, 0) + + # computation.vm_state.logger.debug( + # "SELFDESTRUCT: %s (%s) -> %s", + # encode_hex(computation.msg.storage_address), + # local_balance, + # encode_hex(beneficiary)) + + # 3rd: Register the account to be deleted + computation.registerAccountForDeletion(beneficiary) + raise newException(Halt, "SELFDESTRUCT") + + +proc returnOp*(computation) = + let (startPosition, size) = stack.popInt(2) + computation.extendMemory(startPosition, size) + let output = memory.read(startPosition, size).toCString + computation.output = output + raise newException(Halt, "RETURN") + +proc revert*(computation) = + let (startPosition, size) = stack.popInt(2) + computation.extendMemory(startPosition, size) + let output = memory.read(startPosition, size).toCString + computation.output = output + raise newException(Revert, $output) + +proc selfdestruct*(computation) = + let beneficiary = forceBytesToAddress(stack.popBinary) + selfdestruct(computation, beneficiary) + raise newException(Halt, "SELFDESTRUCT") + diff --git a/src/runner.nim b/src/runner.nim index 6bf3247b4..cc62548f8 100644 --- a/src/runner.nim +++ b/src/runner.nim @@ -2,7 +2,7 @@ import strformat, strutils, tables, macros, constants, bigints, errors, logging, vm_state, vm / [gas_meter, stack, code_stream, memory, message, value, gas_costs], db / chain, computation, opcode, opcode_values, utils / [header, address], - logic / [arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call] + logic / [arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call, system_ops] var opcodes = initOpcodes: # arithmetic @@ -96,6 +96,10 @@ var opcodes = initOpcodes: Op.Invalid: GAS_ZERO invalidOp + # system + Op.Return: 0.i256 returnOp + Op.SelfDestruct: GAS_SELF_DESTRUCT_COST selfdestruct + # call opcodes[Op.Call] = Call(kind: Op.Call) @@ -104,9 +108,7 @@ opcodes[Op.DelegateCall] = DelegateCall(kind: Op.DelegateCall) # system -# Op.Create: GAS_CREATE create -# Op.Return: 0.i256 returnOp -# Op.SelfDestruct: GAS_SELF_DESTRUCT_COST selfDestruct +opcodes[Op.Create] = Create(kind: Op.Create) var mem = newMemory(pow(1024.int256, 2))