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 ## stAttackTest
```diff ```diff
ContractCreationSpam.json Skip 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 ## stBadOpcode
```diff ```diff
+ badOpcodes.json OK + 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 OK: 0/130 Fail: 0/130 Skip: 130/130
---TOTAL--- ---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/[computation, interpreter_dispatch, message],
../vm/interpreter/vm_forks ../vm/interpreter/vm_forks
proc contractCall*(tx: Transaction, vmState: BaseVMState, sender: EthAddress, forkOverride=none(Fork)): GasInt = proc processTransaction*(tx: Transaction, sender: EthAddress, vmState: BaseVMState, 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 =
## Process the transaction, write the results to db. ## Process the transaction, write the results to db.
## Returns amount of ETH to be rewarded to miner ## Returns amount of ETH to be rewarded to miner
trace "Sender", sender trace "Sender", sender
trace "txHash", rlpHash = tx.rlpHash 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 upfrontGasCost = tx.gasLimit.u256 * tx.gasPrice.u256
let upfrontCost = upfrontGasCost + tx.value var balance = vmState.readOnlyStateDb().getBalance(sender)
var balance = db.getBalance(sender) if balance < upfrontGasCost:
if balance < upfrontCost: return tx.gasLimit
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
db.incNonce(sender) vmState.mutateStateDB:
db.setBalance(sender, balance) db.incNonce(sender)
if transactionFailed: return db.subBalance(sender, upfrontGasCost)
# TODO: Run the vm with proper fork var computation = setupComputation(vmState, tx, sender, forkOverride)
if tx.isContractCreation: result = tx.gasLimit
result = tx.contractCreate(vmState, sender)
else: if execComputation(computation):
result = tx.contractCall(vmState, sender) if tx.isContractCreation:
computation.writeContract()
result = computation.refundGas(tx, sender)
type type
# TODO: these types need to be removed # TODO: these types need to be removed

View File

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

View File

@ -13,7 +13,6 @@
# being mostly used for short-term regression prevention. # being mostly used for short-term regression prevention.
func allowedFailingGeneralStateTest*(folder, name: string): bool = func allowedFailingGeneralStateTest*(folder, name: string): bool =
let allowedFailingGeneralStateTests = @[ let allowedFailingGeneralStateTests = @[
"CrashingTransaction.json",
"callcallcallcode_001.json", "callcallcallcode_001.json",
"callcallcallcode_001.json", "callcallcallcode_001.json",
"callcallcode_01.json", "callcallcode_01.json",

View File

@ -50,14 +50,8 @@ proc testFixtureIndexes(prevStateRoot: Hash256, header: BlockHeader, pre: JsonNo
db.addBalance(header.coinbase, 0.u256) db.addBalance(header.coinbase, 0.u256)
return return
let gasCost = tx.gasLimit.u256 * tx.gasPrice.u256
vmState.mutateStateDB: vmState.mutateStateDB:
db.incNonce(sender) let gasUsed = tx.processTransaction(sender, vmState, some(fork))
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))
db.addBalance(header.coinbase, gasUsed.u256 * tx.gasPrice.u256) db.addBalance(header.coinbase, gasUsed.u256 * tx.gasPrice.u256)
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) = proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =