-
Notifications
You must be signed in to change notification settings - Fork 649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sharding[VM,Block,Transaction,Message] and sharding transaction/message execution logic #238
Changes from all commits
6231f21
49b4b19
95f3898
7bc0cd4
d138c48
09854e9
e82809c
a6abcdc
efd0f23
88f4774
22fbc72
9c5775c
8536cd5
980dddf
2646a10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,3 +13,6 @@ | |
from .byzantium import ( # noqa: F401 | ||
ByzantiumVM, | ||
) | ||
from .sharding import ( # noqa: F401 | ||
ShardingVM, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
from evm.constants import ( | ||
ENTRY_POINT, | ||
) | ||
|
||
from evm.exceptions import ( | ||
ContractCreationCollision, | ||
) | ||
|
||
from evm.vm.message import ( | ||
ShardingMessage, | ||
) | ||
from evm.vm.vm_state import ( | ||
VMState, | ||
) | ||
|
||
from evm.utils.address import ( | ||
generate_create2_contract_address, | ||
) | ||
from evm.utils.hexadecimal import ( | ||
encode_hex, | ||
) | ||
from evm.utils.keccak import ( | ||
keccak, | ||
) | ||
|
||
from ..byzantium import ByzantiumVM | ||
from ..frontier.constants import ( | ||
REFUND_SELFDESTRUCT, | ||
) | ||
from .computation import ShardingComputation | ||
from .validation import validate_sharding_transaction | ||
from .blocks import ShardingBlock | ||
|
||
|
||
def _execute_sharding_transaction(vm, transaction): | ||
# | ||
# 1) Pre Computation | ||
# | ||
|
||
# Validate the transaction | ||
transaction.validate() | ||
|
||
vm.validate_transaction(transaction) | ||
|
||
gas_fee = transaction.gas * transaction.gas_price | ||
with vm.state.state_db() as state_db: | ||
# Buy Gas | ||
state_db.delta_balance(transaction.to, -1 * gas_fee) | ||
|
||
# Setup VM Message | ||
message_gas = transaction.gas - transaction.intrinsic_gas | ||
|
||
if transaction.code: | ||
contract_address = generate_create2_contract_address( | ||
b'', | ||
transaction.code, | ||
) | ||
data = b'' | ||
code = transaction.code | ||
is_create = True | ||
else: | ||
contract_address = None | ||
data = transaction.data | ||
code = state_db.get_code(transaction.to) | ||
is_create = False | ||
|
||
vm.logger.info( | ||
( | ||
"TRANSACTION: to: %s | gas: %s | " | ||
"gas-price: %s | data-hash: %s | code-hash: %s" | ||
), | ||
encode_hex(transaction.to), | ||
transaction.gas, | ||
transaction.gas_price, | ||
encode_hex(keccak(transaction.data)), | ||
encode_hex(keccak(transaction.code)), | ||
) | ||
|
||
message = ShardingMessage( | ||
gas=message_gas, | ||
gas_price=transaction.gas_price, | ||
to=transaction.to, | ||
sender=ENTRY_POINT, | ||
value=0, | ||
data=data, | ||
code=code, | ||
is_create=is_create, | ||
) | ||
|
||
# | ||
# 2) Apply the message to the VM. | ||
# | ||
if message.is_create: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah that's also true, it's my mistake. And I don't see a clear and simple way around this either. Perhaps have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that sounds reasonable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if I'm reading this right, but if what you're suggesting involves mutating the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense. How about setting the
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say go for 2 or 3; keep it simple. |
||
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 = vm.get_computation(message) | ||
computation._error = ContractCreationCollision( | ||
"Address collision while creating contract: {0}".format( | ||
encode_hex(contract_address), | ||
) | ||
) | ||
vm.logger.debug( | ||
"Address collision while creating contract: %s", | ||
encode_hex(contract_address), | ||
) | ||
else: | ||
computation = vm.get_computation(message).apply_create_message() | ||
else: | ||
computation = vm.get_computation(message).apply_message() | ||
|
||
# | ||
# 2) Post Computation | ||
# | ||
# Self Destruct Refunds | ||
num_deletions = len(computation.get_accounts_for_deletion()) | ||
if num_deletions: | ||
computation.gas_meter.refund_gas(REFUND_SELFDESTRUCT * num_deletions) | ||
|
||
# Gas Refunds | ||
gas_remaining = computation.get_gas_remaining() | ||
gas_refunded = computation.get_gas_refund() | ||
gas_used = transaction.gas - gas_remaining | ||
gas_refund = min(gas_refunded, gas_used // 2) | ||
gas_refund_amount = (gas_refund + gas_remaining) * transaction.gas_price | ||
|
||
if gas_refund_amount: | ||
vm.logger.debug( | ||
'TRANSACTION REFUND: %s -> %s', | ||
gas_refund_amount, | ||
encode_hex(message.to), | ||
) | ||
|
||
with vm.state.state_db() as state_db: | ||
state_db.delta_balance(message.to, gas_refund_amount) | ||
|
||
# Miner Fees | ||
transaction_fee = (transaction.gas - gas_remaining - gas_refund) * transaction.gas_price | ||
vm.logger.debug( | ||
'TRANSACTION FEE: %s -> %s', | ||
transaction_fee, | ||
encode_hex(vm.block.header.coinbase), | ||
) | ||
with vm.state.state_db() as state_db: | ||
state_db.delta_balance(vm.block.header.coinbase, transaction_fee) | ||
|
||
# Process Self Destructs | ||
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. | ||
vm.logger.debug('DELETING ACCOUNT: %s', encode_hex(account)) | ||
|
||
# TODO: this balance setting is likely superflous and can be | ||
# removed since `delete_account` does this. | ||
state_db.set_balance(account, 0) | ||
state_db.delete_account(account) | ||
|
||
return computation | ||
|
||
|
||
ShardingVM = ByzantiumVM.configure( | ||
name='ShardingVM', | ||
_computation_class=ShardingComputation, | ||
_block_class=ShardingBlock, | ||
_state_class=VMState, | ||
# Method overrides | ||
validate_transaction=validate_sharding_transaction, | ||
execute_transaction=_execute_sharding_transaction, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from rlp.sedes import ( | ||
CountableList, | ||
) | ||
from evm.rlp.headers import ( | ||
BlockHeader, | ||
) | ||
from evm.vm.forks.homestead.blocks import ( | ||
HomesteadBlock, | ||
) | ||
from .transactions import ( | ||
ShardingTransaction, | ||
) | ||
|
||
|
||
class ShardingBlock(HomesteadBlock): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that it should be If you're using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, the name will be changed later but for now I keep it this way for simplicity. I suppose with new transaction class, there would have to be new block class?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it was discussed but I can't recall the specifics. What do you think about just writing an entirely separate I have some deeper thoughts on the subject that I'll try to write-up since I'm starting to get the feeling that we will need a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree that it's better to write a |
||
transaction_class = ShardingTransaction | ||
fields = [ | ||
('header', BlockHeader), | ||
('transactions', CountableList(transaction_class)), | ||
('uncles', CountableList(BlockHeader)) | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the salt be specified by the transaction somehow (maybe the first 32 bytes of
data
)? Otherwise one can't deploy the same contract twice, or am I missing something?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
salt
could be transaction nonce ifnonce
is not abstracted away eventually. Or if it is, one could simply append data tocode
and treat it assalt
.