Transaction: `runComputation` options for non-standard EVM behaviour
The following four flags are added, to change various steps in EVM processing when a call doesn't come from a real transaction: - `noIntrinsic`: Don't charge intrinsic gas. - `noAccessList`: Don't initialise EIP2929 access list. - `noGasCharge`: Don't charge sender account for gas. - `noRefund`: Don't apply gas refund/burn rule. This is to support RPC and GraphQL `call` operations, which behave differently in some ways from regular transaction calls, and to support some test suites. In EVMC terms, all these alterations can be performed on the host side. Signed-off-by: Jamie Lokier <jamie@shareable.org>
This commit is contained in:
parent
12bf0fd346
commit
306c8e92c2
|
@ -27,6 +27,10 @@ type
|
||||||
value*: HostValue # Value sent from sender to recipient.
|
value*: HostValue # Value sent from sender to recipient.
|
||||||
input*: seq[byte] # Input data.
|
input*: seq[byte] # Input data.
|
||||||
accessList*: AccessList # EIP-2930 (Berlin) tx access list.
|
accessList*: AccessList # EIP-2930 (Berlin) tx access list.
|
||||||
|
noIntrinsic*: bool # Don't charge intrinsic gas.
|
||||||
|
noAccessList*: bool # Don't initialise EIP-2929 access list.
|
||||||
|
noGasCharge*: bool # Don't charge sender account for gas.
|
||||||
|
noRefund*: bool # Don't apply gas refund/burn rule.
|
||||||
|
|
||||||
# Standard call result. (Some fields are beyond what EVMC can return,
|
# Standard call result. (Some fields are beyond what EVMC can return,
|
||||||
# and must only be used from tests because they will not always be set).
|
# and must only be used from tests because they will not always be set).
|
||||||
|
@ -114,7 +118,7 @@ proc setupCall(call: CallParams, useIntrinsic: bool): TransactionHost =
|
||||||
)
|
)
|
||||||
|
|
||||||
var intrinsicGas: GasInt = 0
|
var intrinsicGas: GasInt = 0
|
||||||
if useIntrinsic:
|
if useIntrinsic and not call.noIntrinsic:
|
||||||
intrinsicGas = intrinsicGas(call, vmState.fork)
|
intrinsicGas = intrinsicGas(call, vmState.fork)
|
||||||
|
|
||||||
let host = TransactionHost(
|
let host = TransactionHost(
|
||||||
|
@ -150,9 +154,11 @@ proc runComputation*(call: CallParams): CallResult =
|
||||||
let c = host.computation
|
let c = host.computation
|
||||||
|
|
||||||
# Must come after `setupCall` for correct fork.
|
# Must come after `setupCall` for correct fork.
|
||||||
|
if not call.noAccessList:
|
||||||
initialAccessListEIP2929(call)
|
initialAccessListEIP2929(call)
|
||||||
|
|
||||||
# Charge for gas.
|
# Charge for gas.
|
||||||
|
if not call.noGasCharge:
|
||||||
host.vmState.mutateStateDB:
|
host.vmState.mutateStateDB:
|
||||||
db.subBalance(call.sender, call.gasLimit.u256 * call.gasPrice.u256)
|
db.subBalance(call.sender, call.gasLimit.u256 * call.gasPrice.u256)
|
||||||
|
|
||||||
|
@ -160,14 +166,16 @@ proc runComputation*(call: CallParams): CallResult =
|
||||||
|
|
||||||
# Calculated gas used, taking into account refund rules.
|
# Calculated gas used, taking into account refund rules.
|
||||||
var gasRemaining: GasInt = 0
|
var gasRemaining: GasInt = 0
|
||||||
if not c.shouldBurnGas:
|
if call.noRefund:
|
||||||
|
gasRemaining = c.gasMeter.gasRemaining
|
||||||
|
elif not c.shouldBurnGas:
|
||||||
let maxRefund = (call.gasLimit - c.gasMeter.gasRemaining) div 2
|
let maxRefund = (call.gasLimit - c.gasMeter.gasRemaining) div 2
|
||||||
let refund = min(c.getGasRefund(), maxRefund)
|
let refund = min(c.getGasRefund(), maxRefund)
|
||||||
c.gasMeter.returnGas(refund)
|
c.gasMeter.returnGas(refund)
|
||||||
gasRemaining = c.gasMeter.gasRemaining
|
gasRemaining = c.gasMeter.gasRemaining
|
||||||
|
|
||||||
# Refund for unused gas.
|
# Refund for unused gas.
|
||||||
if gasRemaining > 0:
|
if gasRemaining > 0 and not call.noGasCharge:
|
||||||
host.vmState.mutateStateDB:
|
host.vmState.mutateStateDB:
|
||||||
db.addBalance(call.sender, gasRemaining.u256 * call.gasPrice.u256)
|
db.addBalance(call.sender, gasRemaining.u256 * call.gasPrice.u256)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue