Skip to content
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

Py evm 1466 #1799

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eth/vm/forks/spurious_dragon/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@


# https://github.com/ethereum/EIPs/issues/170
EIP170_CODE_SIZE_LIMIT = 24577
EIP170_CODE_SIZE_LIMIT = 24576 # 2**14 + 2**13
80 changes: 80 additions & 0 deletions tests/core/vm/test_spurious_dragon_computation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from unittest import mock

import pytest
from eth_utils import (
to_canonical_address,
)

from eth import (
Chain,
)
from eth.vm.computation import (
BaseComputation,
)
from eth.vm.forks.spurious_dragon.computation import (
SpuriousDragonComputation,
)
from eth.vm.forks.spurious_dragon.constants import (
EIP170_CODE_SIZE_LIMIT
)
from eth.vm.message import (
Message,
)
from eth.vm.transaction_context import (
BaseTransactionContext,
)

NORMALIZED_ADDRESS_A = "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"
NORMALIZED_ADDRESS_B = "0xcd1722f3947def4cf144679da39c4c32bdc35681"
CANONICAL_ADDRESS_A = to_canonical_address(NORMALIZED_ADDRESS_A)
CANONICAL_ADDRESS_B = to_canonical_address(NORMALIZED_ADDRESS_B)


@pytest.fixture
def make_computation():
message = Message(
to=CANONICAL_ADDRESS_B,
sender=CANONICAL_ADDRESS_A,
value=1,
data=b'',
code=b'',
gas=5000000,
)
transaction_context = BaseTransactionContext(gas_price=1, origin=CANONICAL_ADDRESS_B, )

def _make_computation(chain) -> BaseComputation:
state = chain.get_vm().state
state.set_balance(CANONICAL_ADDRESS_A, 1000)
computation = SpuriousDragonComputation(
state=state,
message=message,
transaction_context=transaction_context,
)

return computation

return _make_computation


@pytest.mark.parametrize('chain_without_block_validation', [Chain, ], indirect=True)
@pytest.mark.parametrize(
'computation_output',
[
b'\x00' * (EIP170_CODE_SIZE_LIMIT + 1),
b'\x00' * EIP170_CODE_SIZE_LIMIT,
b'\x00' * (EIP170_CODE_SIZE_LIMIT - 1),
]
)
def test_computation_output_size_limit(chain_without_block_validation,
make_computation,
computation_output):
computation: BaseComputation = make_computation(chain_without_block_validation)
computation.output = computation_output

with mock.patch.object(SpuriousDragonComputation, 'apply_message', return_value=computation):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mock based approaches tend to be problematic. I'd prefer we test this properly using a contract that actually exceeds this limit so that we can see this fail using non-mock/real mechanisms.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing related to this comment and I agree with piper here, but here's a nice article I found on mocking today written by Ned Batchelder: https://nedbatchelder.com/blog/201908/why_your_mock_doesnt_work.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries @pipermerriam and @voith, currently I am out of my town with limited connectivity, but next week I will give it another try. It will help me to have a better understanding of the code and help with more complicated task.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello guys,

I am stuck for a while, I am trying to deploy a dummy contract to the chain but I am receiving a huge out of gas error. I have introduced the question on stack exchange:

https://ethereum.stackexchange.com/questions/74091/deploy-contract-in-py-evm?noredirect=1#comment90183_74091

The full "test" code (because I haven introduces the asserts yet) is:

@pytest.mark.parametrize('chain_without_block_validation', [MiningChain, ], indirect=True)
def test_computation_output_size_limit(chain_without_block_validation):
    SENDER_PRIVATE_KEY = keys.PrivateKey(
        decode_hex('0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8')
    )

    SENDER = Address(SENDER_PRIVATE_KEY.public_key.to_canonical_address())

    state = chain_without_block_validation.get_vm().state
    state.set_balance(SENDER, 1000)

    vm = chain_without_block_validation.get_vm()
    nonce = vm.state.get_nonce(SENDER)

    vm_tx = vm.create_unsigned_transaction(
        nonce=nonce,
        gas_price=10,
        gas=3138525,
        to=CREATE_CONTRACT_ADDRESS,
        value=0,
        data=b'60606040523415600e57600080fd5b5b603680601c6000396000f30060606040525b600080fd00a165627a7a72305820c9e69aabe54411b89c6b2223932d7349334d3e75c12657355b7ba52c47e4db250029',
    )
    signed_tx = vm_tx.as_signed_transaction(SENDER_PRIVATE_KEY)
    new_block, receipt, c = chain_without_block_validation.apply_transaction(signed_tx)

    print("--------------------------------------------------------")
    print("Computation is error: {}".format(c.is_error))
    if c.is_error:
        print("Computation error: {}".format(c.error))

    print("computation output: {}".format(c.output))
    print("computation output len: {}".format(len(c.output)))

I would appreciate any help :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dherykw how did you go about getting that deployment bytecode. My guess is that there's something wrong with it. The error you're receiving is a standard EVM error so it's probably worth you trying to trace the VM execution to figure out why it's trying to expand the memory to such a large size.

computation.apply_create_message()

if len(computation_output) >= EIP170_CODE_SIZE_LIMIT:
assert computation.is_error
else:
assert not computation.is_error