Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.
Closed
40 changes: 40 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ version: 2.0
common: &common
working_directory: ~/repo
steps:
# TODO: remove this step when `plyvel` gets a Python 3.8 wheel
- run:
name: install LevelDB headers dependency system-wide
command: sudo apt-get install libleveldb-dev
- checkout
- run:
name: checkout fixtures submodule
Expand Down Expand Up @@ -168,6 +172,37 @@ jobs:
environment:
TOXENV: py37-lint

py38-core:
<<: *common
docker:
- image: circleci/python:3.8
environment:
TOXENV: py38-core
py38-database:
<<: *common
docker:
- image: circleci/python:3.8
environment:
TOXENV: py38-database
py38-transactions:
<<: *common
docker:
- image: circleci/python:3.8
environment:
TOXENV: py38-transactions
py38-vm:
<<: *common
docker:
- image: circleci/python:3.8
environment:
TOXENV: py38-vm
py38-lint:
<<: *common
docker:
- image: circleci/python:3.8
environment:
TOXENV: py38-lint

workflows:
version: 2
test:
Expand All @@ -184,12 +219,17 @@ workflows:
- py36-native-blockchain-transition
- py36-vm
- py37-vm
- py38-vm
- py36-core
- py37-core
- py38-core
- py36-transactions
- py37-transactions
- py38-transactions
- py36-database
- py37-database
- py38-database
- py36-docs
- py36-lint
- py37-lint
- py38-lint
19 changes: 16 additions & 3 deletions eth/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,9 +775,9 @@ def __call__(self, computation: 'ComputationAPI') -> None:
def as_opcode(cls: Type[T],
logic_fn: Callable[['ComputationAPI'], None],
mnemonic: str,
gas_cost: int) -> Type[T]:
gas_cost: int) -> T:
Copy link
Contributor Author

@veox veox Dec 6, 2019

Choose a reason for hiding this comment

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

ABC made same as the consumer:

py-evm/eth/vm/opcode.py

Lines 39 to 43 in 3f33ac8

@classmethod
def as_opcode(cls: Type[T],
logic_fn: Callable[..., Any],
mnemonic: str,
gas_cost: int) -> T:

Before the change, mypy said:

eth/vm/opcode.py:40: error: Return type "Opcode" of "as_opcode" incompatible with return type "Type[Opcode]" in supertype "OpcodeAPI"

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I agree with your call here, too. The implementation is clearly returning an Opcode instance instead of class, and would require a lot of refactoring to change (if we even wanted to).

The only thing I'd add it that the ABC docs should update, too.

"""
Class factory method for turning vanilla functions into Opcode classes.
Class factory method for turning vanilla functions into Opcodes.
"""
...

Expand Down Expand Up @@ -1633,6 +1633,16 @@ def state_root(self) -> Hash32:
"""
...

@state_root.setter
def state_root(self, value: Hash32) -> None:
"""
Force-set the state root hash.
"""
# See: https://github.com/python/mypy/issues/4165
# Since we can't also decorate this with abstract method we want to be
# sure that the setter doesn't actually get used as a noop.
raise NotImplementedError

@abstractmethod
def has_root(self, state_root: bytes) -> bool:
"""
Expand Down Expand Up @@ -2287,7 +2297,10 @@ class VirtualMachineAPI(ConfigurableAPI):
extra_data_max_bytes: ClassVar[int]

@abstractmethod
def __init__(self, header: BlockHeaderAPI, chaindb: ChainDatabaseAPI) -> None:
def __init__(self,
header: BlockHeaderAPI,
chaindb: ChainDatabaseAPI,
chain_context: ChainContextAPI) -> None:
"""
Initialize the virtual machine.
"""
Expand Down
8 changes: 4 additions & 4 deletions eth/chains/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ def from_genesis(cls,
# the computed state from the initialized state database.
raise ValidationError(
"The provided genesis state root does not match the computed "
f"genesis state root. Got {state.state_root}. "
f"Expected {genesis_params['state_root']}"
f"genesis state root. Got {state.state_root!r}. "
f"Expected {genesis_params['state_root']!r}"
)

genesis_header = BlockHeader(**genesis_params)
Expand Down Expand Up @@ -438,8 +438,8 @@ def import_block(self,
except HeaderNotFound:
raise ValidationError(
f"Attempt to import block #{block.number}. "
f"Cannot import block {block.hash} before importing "
f"its parent block at {block.header.parent_hash}"
f"Cannot import block {block.hash!r} before importing "
f"its parent block at {block.header.parent_hash!r}"
)

base_header_for_import = self.create_header_from_parent(parent_header)
Expand Down
6 changes: 3 additions & 3 deletions eth/consensus/clique/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ def validate_header_integrity(header: BlockHeaderAPI, epoch_length: int) -> None
)

if header.nonce != NONCE_AUTH and header.nonce != NONCE_DROP:
raise ValidationError(f"Invalid nonce: {header.nonce}")
raise ValidationError(f"Invalid nonce: {header.nonce!r}")

if at_checkpoint and header.nonce != NONCE_DROP:
raise ValidationError(f"Invalid checkpoint nonce: {header.nonce}")
raise ValidationError(f"Invalid checkpoint nonce: {header.nonce!r}")

if len(header.extra_data) < VANITY_LENGTH:
raise ValidationError("Missing vanity bytes in extra data")
Expand All @@ -159,7 +159,7 @@ def validate_header_integrity(header: BlockHeaderAPI, epoch_length: int) -> None
raise ValidationError("Checkpoint header must contain list of signers")

if header.mix_hash != ZERO_HASH32:
raise ValidationError(f"Invalid mix hash: {header.mix_hash}")
raise ValidationError(f"Invalid mix hash: {header.mix_hash!r}")

if header.uncles_hash != EMPTY_UNCLE_HASH:
raise ValidationError(f"Invalid uncle hash: {header.uncle_hash}")
Expand Down
2 changes: 1 addition & 1 deletion eth/consensus/clique/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def validate_for(self,
if not signer_is_kicked and not signer_is_nominated:
raise ValidationError(
"Must either kick an existing signer or nominate a new signer"
f"Subject: {subject} Current signers: {signers}"
f"Subject: {subject!r} Current signers: {signers}"
)


Expand Down
8 changes: 4 additions & 4 deletions eth/consensus/clique/snapshot_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,16 +220,16 @@ def get_snapshot(self, block_number: int, block_hash: Hash32) -> Snapshot:
# Otherwise, we can retrieve it on the fly
header = self._chain_db.get_block_header_by_hash(block_hash)
except HeaderNotFound:
raise SnapshotNotFound(f"Can not get snapshot for {block_hash} at {block_number}")
raise SnapshotNotFound(f"Can not get snapshot for {block_hash!r} at {block_number}")
else:
if header.block_number != block_number:
raise SnapshotNotFound(
f"Can not get snapshot for {block_hash} at {block_number}"
f"Can not get snapshot for {block_hash!r} at {block_number}"
)
else:
return self._create_snapshot_from_checkpoint_header(header)

raise SnapshotNotFound(f"Can not get snapshot for {block_hash} at {block_number}")
raise SnapshotNotFound(f"Can not get snapshot for {block_hash!r} at {block_number}")

def add_snapshot(self, mutable_snapshot: MutableSnapshot) -> Snapshot:
"""
Expand All @@ -256,7 +256,7 @@ def get_snapshot_from_db(self, block_hash: Hash32) -> Snapshot:
encoded_key = self._chain_db.db[key]
except KeyError as e:
raise SnapshotNotFound(
f"Can not get on-disk snapshot for {block_hash}"
f"Can not get on-disk snapshot for {block_hash!r}"
)
else:
return decode_snapshot(encoded_key)
Expand Down
2 changes: 1 addition & 1 deletion eth/db/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def get_block_uncles(self, uncles_hash: Hash32) -> Tuple[BlockHeaderAPI, ...]:
encoded_uncles = self.db[uncles_hash]
except KeyError:
raise HeaderNotFound(
f"No uncles found for hash {uncles_hash}"
f"No uncles found for hash {uncles_hash!r}"
)
else:
return tuple(rlp.decode(encoded_uncles, sedes=rlp.sedes.CountableList(BlockHeader)))
Expand Down
4 changes: 2 additions & 2 deletions eth/tools/fixtures/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ def verify_state(expected_state: AccountState, state: StateAPI) -> None:
if field == 'balance':
error_messages.append(
f"{to_normalized_address(account)}(balance) | "
f"Actual: {actual_value} | Expected: {expected_value} | "
f"Actual: {actual_value!r} | Expected: {expected_value!r} | "
f"Delta: {cast(int, actual_value) - cast(int, expected_value)}"
)
else:
error_messages.append(
f"{to_normalized_address(account)}({field}) | "
f"Actual: {actual_value} | Expected: {expected_value}"
f"Actual: {actual_value!r} | Expected: {expected_value!r}"
)
raise AssertionError(
f"State DB did not match expected state on {len(error_messages)} values:{new_line}"
Expand Down
2 changes: 1 addition & 1 deletion eth/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def validate_lt(value: int, maximum: int, title: str="Value") -> None:
def validate_canonical_address(value: Address, title: str="Value") -> None:
if not isinstance(value, bytes) or not len(value) == 20:
raise ValidationError(
f"{title} {value} is not a valid canonical address"
f"{title} {value!r} is not a valid canonical address"
)


Expand Down
2 changes: 1 addition & 1 deletion eth/vm/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ def validate_block(self, block: BlockAPI) -> None:
if tx_root_hash != block.header.transaction_root:
raise ValidationError(
f"Block's transaction_root ({block.header.transaction_root}) "
f"does not match expected value: {tx_root_hash}"
f"does not match expected value: {tx_root_hash!r}"
)

if len(block.uncles) > MAX_UNCLES:
Expand Down
2 changes: 1 addition & 1 deletion eth/vm/forks/frontier/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def validate_frontier_transaction(state: StateAPI,

if sender_balance < gas_cost:
raise ValidationError(
f"Sender {transaction.sender} cannot afford txn gas "
f"Sender {transaction.sender!r} cannot afford txn gas "
f"{gas_cost} with account balance {sender_balance}"
)

Expand Down
2 changes: 1 addition & 1 deletion eth/vm/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(
self,
db: AtomicDatabaseAPI,
execution_context: ExecutionContextAPI,
state_root: bytes) -> None:
state_root: Hash32) -> None:
Copy link
Contributor Author

@veox veox Dec 6, 2019

Choose a reason for hiding this comment

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

@carver This is the example of cargo-culting I mentioned on gitter: consumer changed to fit the ABC; previous commit went the other way (ABC changed to appease the consumer).


mypy said (before the change):

eth/vm/state.py:57: error: Argument 2 to "AccountDatabaseAPI" has incompatible type "bytes"; expected "Hash32"

... so I gave it exactly what it asked. But I don't know if it's right or not.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, in this case, it looks like the right thing to do to go with Hash32, since it's logically the hash of the root node. 👍

Copy link
Contributor Author

@veox veox Dec 10, 2019

Choose a reason for hiding this comment

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

Should has_root() of AccountDB (and ABC AccountDatabaseAPI) have a state_root argument that's Hash32 also?..

py-evm/eth/db/account.py

Lines 135 to 136 in 0d79bb6

def has_root(self, state_root: bytes) -> bool:
return state_root in self._batchtrie

This doesn't produce a linting error; just wondering if this would be right to change now, too.

self._db = db
self.execution_context = execution_context
self._account_db = self.get_account_db_class()(db, state_root)
Expand Down
9 changes: 5 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"eth-bloom>=1.0.3,<2.0.0",
"eth-keys>=0.2.1,<0.3.0",
"eth-typing>=2.2.0,<3.0.0",
"eth-utils>=1.7.0,<2.0.0",
"eth-utils>=1.8.0,<2.0.0",
"lru-dict>=1.1.6",
"mypy_extensions>=0.4.1,<1.0.0",
"py-ecc>=1.4.7,<2.0.0",
Expand All @@ -23,14 +23,14 @@
# Installing these libraries may make the evm perform better than
# using the default fallbacks though.
'eth-extra': [
"coincurve>=10.0.0,<11.0.0",
"coincurve>=13.0.0,<14.0.0",
"eth-hash[pysha3];implementation_name=='cpython'",
"eth-hash[pycryptodome];implementation_name=='pypy'",
"plyvel>=1.0.5,<1.2.0",
],
'test': [
"factory-boy==2.11.1",
"hypothesis==3.69.5",
"hypothesis==4.50.6",
"pexpect>=4.6, <5",
"pytest>=5.1.3,<6",
"pytest-asyncio>=0.10.0,<0.11",
Expand All @@ -41,7 +41,7 @@
'lint': [
"flake8==3.5.0",
"flake8-bugbear==18.8.0",
"mypy==0.701",
"mypy==0.750",
],
'benchmark': [
"termcolor>=1.1.0,<2.0.0",
Expand Down Expand Up @@ -115,5 +115,6 @@
'Natural Language :: English',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
)
7 changes: 5 additions & 2 deletions tests/core/code-stream/test_code_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,10 @@ def test_new_vs_reference_code_stream_iter(bytecode):
assert latest.program_counter == reference.program_counter


@given(read_len=st.integers(min_value=0), bytecode=st.binary(max_size=128))
@given(
read_len=st.integers(min_value=0, max_value=2048),
Copy link
Contributor Author

@veox veox Dec 2, 2019

Choose a reason for hiding this comment

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

This (here and in test below) certainly requires review.

max_value=2**63-1 works just fine, too. 2**63 (gets passed implicitly if max_value not present) is what breaks the test.


See also commit message, copied below.


A failure happens because the underlying io.BytesIO.read(size) call gets a size=9223372036854775808. That's (2^63), but it seems that the biggest size that BytesIO can read is (2^63)-1.

The error surfaced after an update of package hypothesis from v3 to v4 (version that is latest ATM), and is possibly an issue from upstream. Or it could be ours.

Anyway, limiting read_len fixes the issue. Could use (2^63)-1, too, but considering that bytecode max_size is limited, I don't see the point.


Likely a limitation of CPython; I'd guess the read index is an int64 on 64-bit machines (since -1 is a valid value). Also possible that hypothesis doesn't know.

Copy link
Member

Choose a reason for hiding this comment

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

This seems fine to me.

bytecode=st.binary(max_size=128)
)
def test_new_vs_reference_code_stream_read(read_len, bytecode):
reference = SlowCodeStream(bytecode)
latest = CodeStream(bytecode)
Expand All @@ -217,7 +220,7 @@ def test_new_vs_reference_code_stream_read(read_len, bytecode):

@given(
read_idx=st.integers(min_value=0, max_value=10),
read_len=st.integers(min_value=0),
read_len=st.integers(min_value=0, max_value=2048),
bytecode=st.binary(max_size=128),
)
def test_new_vs_reference_code_stream_read_during_iter(read_idx, read_len, bytecode):
Expand Down
5 changes: 3 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[tox]
envlist=
py{36,37}-{core,database,transactions,vm}
py{36,37,38}-{core,database,transactions,vm}
py36-benchmark
py36-native-blockchain-{frontier,homestead,tangerine_whistle,spurious_dragon,byzantium,constantinople,petersburg,istanbul,metropolis,transition}
py{36,37}-lint
py{36,37,38}-lint
py36-docs

[flake8]
Expand Down Expand Up @@ -41,6 +41,7 @@ deps =
basepython =
py36: python3.6
py37: python3.7
py38: python3.8


[testenv:py36-docs]
Expand Down