initial contract call/create unification

This commit is contained in:
andri lim 2019-03-07 14:10:05 +07:00
parent a53a543569
commit fdf9e04108
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
5 changed files with 41 additions and 81 deletions

View File

@ -53,9 +53,9 @@ OK: 0/46 Fail: 0/46 Skip: 46/46
## stAttackTest
```diff
ContractCreationSpam.json Skip
CrashingTransaction.json Skip
+ CrashingTransaction.json OK
```
OK: 0/2 Fail: 0/2 Skip: 2/2
OK: 1/2 Fail: 0/2 Skip: 1/2
## stBadOpcode
```diff
+ badOpcodes.json OK
@ -2520,4 +2520,4 @@ OK: 0/133 Fail: 0/133 Skip: 133/133
OK: 0/130 Fail: 0/130 Skip: 130/130
---TOTAL---
OK: 1179/2334 Fail: 0/2334 Skip: 1155/2334
OK: 1180/2334 Fail: 0/2334 Skip: 1154/2334

View File

@ -6,55 +6,28 @@ import options,
../vm/[computation, interpreter_dispatch, message],
../vm/interpreter/vm_forks
proc contractCall*(tx: Transaction, vmState: BaseVMState, sender: EthAddress, forkOverride=none(Fork)): GasInt =
var db = vmState.accountDb
var computation = setupComputation(vmState, tx, sender, forkOverride)
result = tx.gasLimit
if execComputation(computation):
let
gasRemaining = computation.gasMeter.gasRemaining
gasRefunded = computation.getGasRefund()
gasUsed = tx.gasLimit - gasRemaining
gasRefund = min(gasRefunded, gasUsed div 2)
gasRefundAmount = (gasRemaining + gasRefund).u256 * tx.gasPrice.u256
db.addBalance(sender, gasRefundAmount)
return (gasUsed - gasRefund)
proc processTransaction*(tx: Transaction, sender: EthAddress, vmState: BaseVMState): GasInt =
proc processTransaction*(tx: Transaction, sender: EthAddress, vmState: BaseVMState, forkOverride=none(Fork)): GasInt =
## Process the transaction, write the results to db.
## Returns amount of ETH to be rewarded to miner
trace "Sender", sender
trace "txHash", rlpHash = tx.rlpHash
var db = vmState.accountDb
var transactionFailed = false
# TODO: combine/refactor re validate
let upfrontGasCost = tx.gasLimit.u256 * tx.gasPrice.u256
let upfrontCost = upfrontGasCost + tx.value
var balance = db.getBalance(sender)
if balance < upfrontCost:
if balance <= upfrontGasCost:
result = (balance div tx.gasPrice.u256).truncate(GasInt)
balance = 0.u256
else:
result = tx.gasLimit
balance -= upfrontGasCost
transactionFailed = true
else:
balance -= upfrontGasCost
var balance = vmState.readOnlyStateDb().getBalance(sender)
if balance < upfrontGasCost:
return tx.gasLimit
db.incNonce(sender)
db.setBalance(sender, balance)
if transactionFailed: return
vmState.mutateStateDB:
db.incNonce(sender)
db.subBalance(sender, upfrontGasCost)
# TODO: Run the vm with proper fork
if tx.isContractCreation:
result = tx.contractCreate(vmState, sender)
else:
result = tx.contractCall(vmState, sender)
var computation = setupComputation(vmState, tx, sender, forkOverride)
result = tx.gasLimit
if execComputation(computation):
if tx.isContractCreation:
computation.writeContract()
result = computation.refundGas(tx, sender)
type
# TODO: these types need to be removed

View File

@ -87,39 +87,33 @@ proc execComputation*(computation: var BaseComputation): bool =
snapshot.revert()
if computation.tracingEnabled: computation.traceError()
proc contractCreate*(tx: Transaction, vmState: BaseVMState, sender: EthAddress, forkOverride=none(Fork)): GasInt =
doAssert tx.isContractCreation
var c = setupComputation(vmState, tx, sender, forkOverride)
result = tx.gasLimit
proc refundGas*(computation: BaseComputation, tx: Transaction, sender: EthAddress): GasInt =
let
gasRemaining = computation.gasMeter.gasRemaining
gasRefunded = computation.getGasRefund()
gasUsed = tx.gasLimit - gasRemaining
gasRefund = min(gasRefunded, gasUsed div 2)
if execComputation(c):
var db = vmState.accountDb
let
gasRemaining = c.gasMeter.gasRemaining
gasRefunded = c.getGasRefund()
gasUsed = tx.gasLimit - gasRemaining
gasRefund = min(gasRefunded, gasUsed div 2)
computation.vmState.mutateStateDB:
db.addBalance(sender, (gasRemaining + gasRefund).u256 * tx.gasPrice.u256)
var codeCost = c.gasCosts[Create].m_handler(0, 0, c.output.len)
result = gasUsed - gasRefund
# This apparently is not supposed to actually consume the gas, just be able to,
# for purposes of accounting. Py-EVM apparently does consume the gas, but it is
# not matching observed blockchain balances if consumeGas is called.
let contractAddress = c.msg.storageAddress
if not c.isSuicided(contractAddress):
# make changes only if it not selfdestructed
if gasRemaining >= codeCost:
db.setCode(contractAddress, c.output.toRange)
else:
# XXX: Homestead behaves differently; reverts state on gas failure
# https://github.com/ethereum/py-evm/blob/master/eth/vm/forks/homestead/computation.py
codeCost = 0
proc writeContract*(computation: var BaseComputation) =
let codeCost = computation.gasCosts[Create].m_handler(0, 0, computation.output.len)
let contractAddress = computation.msg.storageAddress
if not computation.isSuicided(contractAddress):
# make changes only if it not selfdestructed
if computation.gasMeter.gasRemaining >= codeCost:
computation.gasMeter.consumeGas(codeCost, reason = "Write contract code for CREATE")
computation.vmState.mutateStateDB:
db.setCode(contractAddress, computation.output.toRange)
else:
# XXX: Homestead behaves differently; reverts state on gas failure
# https://github.com/ethereum/py-evm/blob/master/eth/vm/forks/homestead/computation.py
computation.vmState.mutateStateDB:
db.setCode(contractAddress, ByteRange())
db.addBalance(sender, (gasRemaining + gasRefund - codeCost).u256 * tx.gasPrice.u256)
return (gasUsed - gasRefund + codeCost)
#[
method executeTransaction(vmState: BaseVMState, transaction: Transaction): (BaseComputation, BlockHeader) {.base.}=
# Execute the transaction in the vm

View File

@ -12,8 +12,7 @@
# table once, but notion's that it should shrink reasonable quickly and disappear,
# being mostly used for short-term regression prevention.
func allowedFailingGeneralStateTest*(folder, name: string): bool =
let allowedFailingGeneralStateTests = @[
"CrashingTransaction.json",
let allowedFailingGeneralStateTests = @[
"callcallcallcode_001.json",
"callcallcallcode_001.json",
"callcallcode_01.json",

View File

@ -50,14 +50,8 @@ proc testFixtureIndexes(prevStateRoot: Hash256, header: BlockHeader, pre: JsonNo
db.addBalance(header.coinbase, 0.u256)
return
let gasCost = tx.gasLimit.u256 * tx.gasPrice.u256
vmState.mutateStateDB:
db.incNonce(sender)
db.subBalance(sender, gasCost)
let gasUsed = if tx.isContractCreation and tx.payload.len > 0:
tx.contractCreate(vmState, sender, some(fork))
else:
tx.contractCall(vmState, sender, some(fork))
let gasUsed = tx.processTransaction(sender, vmState, some(fork))
db.addBalance(header.coinbase, gasUsed.u256 * tx.gasPrice.u256)
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =