Skip to content

Commit

Permalink
update sharding computation to new computation logic introduced in #244
Browse files Browse the repository at this point in the history
  • Loading branch information
NIC619 committed Jan 5, 2018
1 parent d3db2e5 commit 519afdc
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 108 deletions.
121 changes: 13 additions & 108 deletions evm/vm/forks/sharding/__init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
from evm.constants import (
ENTRY_POINT,
STACK_DEPTH_LIMIT,
)

from evm.exceptions import (
InsufficientFunds,
StackDepthLimit,
ContractCreationCollision,
OutOfGas,
)

from evm.vm.message import (
ShardingMessage,
)
from evm.vm.computation import (
Computation,
from evm.vm.vm_state import (
VMState,
)

from evm.utils.address import (
Expand All @@ -28,13 +24,10 @@
)

from ..byzantium import ByzantiumVM
from ..spurious_dragon.constants import (
EIP170_CODE_SIZE_LIMIT,
GAS_CODEDEPOSIT,
)
from ..frontier.constants import (
REFUND_SELFDESTRUCT,
)
from .computation import ShardingComputation
from .validation import validate_sharding_transaction
from .blocks import ShardingBlock

Expand All @@ -50,7 +43,7 @@ def _execute_sharding_transaction(vm, transaction):
vm.validate_transaction(transaction)

gas_fee = transaction.gas * transaction.gas_price
with vm.state_db() as state_db:
with vm.state.state_db() as state_db:
# Buy Gas
state_db.delta_balance(transaction.to, -1 * gas_fee)

Expand Down Expand Up @@ -98,13 +91,13 @@ def _execute_sharding_transaction(vm, transaction):
# 2) Apply the message to the VM.
#
if message.is_create:
with vm.state_db(read_only=True) as state_db:
with vm.state.state_db(read_only=True) as state_db:
is_collision = state_db.account_has_code_or_nonce(contract_address)

if is_collision:
# The address of the newly created contract has collided
# with an existing contract address.
computation = Computation(vm, message)
computation = vm.get_computation(message)
computation._error = ContractCreationCollision(
"Address collision while creating contract: {0}".format(
encode_hex(contract_address),
Expand All @@ -115,9 +108,9 @@ def _execute_sharding_transaction(vm, transaction):
encode_hex(contract_address),
)
else:
computation = vm.apply_create_message(message)
computation = vm.get_computation(message).apply_create_message()
else:
computation = vm.apply_message(message)
computation = vm.get_computation(message).apply_message()

#
# 2) Post Computation
Expand All @@ -141,7 +134,7 @@ def _execute_sharding_transaction(vm, transaction):
encode_hex(message.to),
)

with vm.state_db() as state_db:
with vm.state.state_db() as state_db:
state_db.delta_balance(message.to, gas_refund_amount)

# Miner Fees
Expand All @@ -151,11 +144,11 @@ def _execute_sharding_transaction(vm, transaction):
transaction_fee,
encode_hex(vm.block.header.coinbase),
)
with vm.state_db() as state_db:
with vm.state.state_db() as state_db:
state_db.delta_balance(vm.block.header.coinbase, transaction_fee)

# Process Self Destructs
with vm.state_db() as state_db:
with vm.state.state_db() as state_db:
for account, beneficiary in computation.get_accounts_for_deletion():
# TODO: need to figure out how we prevent multiple selfdestructs from
# the same account and if this is the right place to put this.
Expand All @@ -169,100 +162,12 @@ def _execute_sharding_transaction(vm, transaction):
return computation


def _apply_sharding_message(vm, message):
snapshot = vm.snapshot()

if message.depth > STACK_DEPTH_LIMIT:
raise StackDepthLimit("Stack depth limit reached")

if message.should_transfer_value and message.value:
with vm.state_db() as state_db:
sender_balance = state_db.get_balance(message.sender)

if sender_balance < message.value:
raise InsufficientFunds(
"Insufficient funds: {0} < {1}".format(sender_balance, message.value)
)

state_db.delta_balance(message.sender, -1 * message.value)
state_db.delta_balance(message.storage_address, message.value)

vm.logger.debug(
"TRANSFERRED: %s from %s -> %s",
message.value,
encode_hex(message.sender),
encode_hex(message.storage_address),
)

with vm.state_db() as state_db:
state_db.touch_account(message.storage_address)

computation = vm.apply_computation(message)

if computation.is_error:
vm.revert(snapshot)
else:
vm.commit(snapshot)

return computation


def _apply_sharding_create_message(vm, message):
# Remove EIP160 nonce increment but keep EIP170 contract code size limit
snapshot = vm.snapshot()

computation = vm.apply_message(message)

if computation.is_error:
vm.revert(snapshot)
return computation
else:
contract_code = computation.output

if contract_code and len(contract_code) >= EIP170_CODE_SIZE_LIMIT:
computation._error = OutOfGas(
"Contract code size exceeds EIP170 limit of {0}. Got code of "
"size: {1}".format(
EIP170_CODE_SIZE_LIMIT,
len(contract_code),
)
)
vm.revert(snapshot)
elif contract_code:
contract_code_gas_cost = len(contract_code) * GAS_CODEDEPOSIT
try:
computation.gas_meter.consume_gas(
contract_code_gas_cost,
reason="Write contract code for CREATE",
)
except OutOfGas as err:
# Different from Frontier: reverts state on gas failure while
# writing contract code.
computation._error = err
vm.revert(snapshot)
else:
if vm.logger:
vm.logger.debug(
"SETTING CODE: %s -> length: %s | hash: %s",
encode_hex(message.storage_address),
len(contract_code),
encode_hex(keccak(contract_code))
)

with vm.state_db() as state_db:
state_db.set_code(message.storage_address, contract_code)
vm.commit(snapshot)
else:
vm.commit(snapshot)
return computation


ShardingVM = ByzantiumVM.configure(
name='ShardingVM',
_computation_class=ShardingComputation,
_block_class=ShardingBlock,
_state_class=VMState,
# Method overrides
validate_transaction=validate_sharding_transaction,
apply_message=_apply_sharding_message,
apply_create_message=_apply_sharding_create_message,
execute_transaction=_execute_sharding_transaction,
)
115 changes: 115 additions & 0 deletions evm/vm/forks/sharding/computation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from evm.constants import (
STACK_DEPTH_LIMIT,
)
from evm.exceptions import (
OutOfGas,
InsufficientFunds,
StackDepthLimit,
)
from evm.utils.hexadecimal import (
encode_hex,
)
from evm.utils.keccak import (
keccak,
)

from ..spurious_dragon.computation import (
SpuriousDragonComputation,
)
from ..spurious_dragon.constants import (
EIP170_CODE_SIZE_LIMIT,
GAS_CODEDEPOSIT,
)


class ShardingComputation(SpuriousDragonComputation):
def apply_message(self):
snapshot = self.vm_state.snapshot()

if self.msg.depth > STACK_DEPTH_LIMIT:
raise StackDepthLimit("Stack depth limit reached")

if self.msg.should_transfer_value and self.msg.value:
with self.vm_state.state_db() as state_db:
sender_balance = state_db.get_balance(self.msg.sender)

if sender_balance < self.msg.value:
raise InsufficientFunds(
"Insufficient funds: {0} < {1}".format(sender_balance, self.msg.value)
)

state_db.delta_balance(self.msg.sender, -1 * self.msg.value)
state_db.delta_balance(self.msg.storage_address, self.msg.value)

self.logger.debug(
"TRANSFERRED: %s from %s -> %s",
self.msg.value,
encode_hex(self.msg.sender),
encode_hex(self.msg.storage_address),
)

with self.vm_state.state_db() as state_db:
state_db.touch_account(self.msg.storage_address)

computation = self.apply_computation(
self.vm_state,
self.msg,
self.opcodes,
self.precompiles,
)

if computation.is_error:
self.vm_state.revert(snapshot)
else:
self.vm_state.commit(snapshot)

return computation

def apply_create_message(self):
# Remove EIP160 nonce increment but keep EIP170 contract code size limit
snapshot = self.vm_state.snapshot()

computation = self.apply_message()

if computation.is_error:
self.vm_state.revert(snapshot)
return computation
else:
contract_code = computation.output

if contract_code and len(contract_code) >= EIP170_CODE_SIZE_LIMIT:
computation._error = OutOfGas(
"Contract code size exceeds EIP170 limit of {0}. Got code of "
"size: {1}".format(
EIP170_CODE_SIZE_LIMIT,
len(contract_code),
)
)
self.vm_state.revert(snapshot)
elif contract_code:
contract_code_gas_cost = len(contract_code) * GAS_CODEDEPOSIT
try:
computation.gas_meter.consume_gas(
contract_code_gas_cost,
reason="Write contract code for CREATE",
)
except OutOfGas as err:
# Different from Frontier: reverts state on gas failure while
# writing contract code.
computation._error = err
self.vm_state.revert(snapshot)
else:
if self.logger:
self.logger.debug(
"SETTING CODE: %s -> length: %s | hash: %s",
encode_hex(self.msg.storage_address),
len(contract_code),
encode_hex(keccak(contract_code))
)

with self.vm_state.state_db() as state_db:
state_db.set_code(self.msg.storage_address, contract_code)
self.vm_state.commit(snapshot)
else:
self.vm_state.commit(snapshot)
return computation

0 comments on commit 519afdc

Please sign in to comment.