mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 21:34:33 +00:00
initial contract call/create unification
This commit is contained in:
parent
a53a543569
commit
fdf9e04108
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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) =
|
||||
|
Loading…
x
Reference in New Issue
Block a user