diff --git a/.circleci/config.yml b/.circleci/config.yml index 98d2367c9..02871530e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -30,11 +30,6 @@ jobs: - ./venv key: v1-dependencies-{{ checksum "requirements.txt" }} - # run tests! - # this example uses Django's built-in test-runner - # other common Python testing frameworks include pytest and nose - # https://pytest.org - # https://nose.readthedocs.io - run: name: run tests command: | @@ -43,4 +38,4 @@ jobs: - store_artifacts: path: test-reports - destination: test-reports \ No newline at end of file + destination: test-reports diff --git a/.gitignore b/.gitignore index f9a966cea..dfb38d170 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ /venv /.pytest_cache -build/phase0/spec.py +build/ diff --git a/Makefile b/Makefile index 8be65fd44..593ea8bf4 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,15 @@ SPEC_DIR = ./specs SCRIPT_DIR = ./scripts BUILD_DIR = ./build +UTILS_DIR = ./utils .PHONY: clean all $(BUILD_DIR)/phase0 $(BUILD_DIR)/phase0: + mkdir -p $@ python3 $(SCRIPT_DIR)/phase0/build_spec.py $(SPEC_DIR)/core/0_beacon-chain.md $@/spec.py + mkdir -p $@/utils + cp $(UTILS_DIR)/phase0/* $@/utils + cp $(UTILS_DIR)/phase0/state_transition.py $@ + touch $@/__init__.py $@/utils/__init__.py diff --git a/build/phase0/spec.py b/build/phase0/spec.py index 8c05b1208..3fd82c33f 100644 --- a/build/phase0/spec.py +++ b/build/phase0/spec.py @@ -1,5 +1,5 @@ -from build.utils.minimal_ssz import * -from build.utils.bls_stub import * +from build.phase0.utils.minimal_ssz import * +from build.phase0.utils.bls_stub import * def int_to_bytes1(x): return x.to_bytes(1, 'little') def int_to_bytes2(x): return x.to_bytes(2, 'little') def int_to_bytes3(x): return x.to_bytes(3, 'little') diff --git a/build/phase0/state_transition.py b/build/phase0/state_transition.py index 2bd33f6d6..170f647ab 100644 --- a/build/phase0/state_transition.py +++ b/build/phase0/state_transition.py @@ -1,4 +1,4 @@ -import build.phase0.spec as spec +from . import spec from typing import ( @@ -9,7 +9,7 @@ from typing import ( Tuple, ) -from build.phase0.spec import ( +from .spec import ( BeaconState, BeaconBlock, ) diff --git a/build/utils/monkey_patches.py b/build/utils/monkey_patches.py deleted file mode 100644 index 8a35b8f27..000000000 --- a/build/utils/monkey_patches.py +++ /dev/null @@ -1,29 +0,0 @@ -# Monkey patch validator shuffling cache -_get_shuffling = get_shuffling -shuffling_cache = {} -def get_shuffling(seed: Bytes32, - validators: List[Validator], - epoch: Epoch) -> List[List[ValidatorIndex]]: - - param_hash = (seed, hash_tree_root(validators, [Validator]), epoch) - - if param_hash in shuffling_cache: - # print("Cache hit, epoch={0}".format(epoch)) - return shuffling_cache[param_hash] - else: - # print("Cache miss, epoch={0}".format(epoch)) - ret = _get_shuffling(seed, validators, epoch) - shuffling_cache[param_hash] = ret - return ret - - -# Monkey patch hash cache -_hash = hash -hash_cache = {} -def hash(x): - if x in hash_cache: - return hash_cache[x] - else: - ret = _hash(x) - hash_cache[x] = ret - return ret diff --git a/scripts/phase0/build_spec.py b/scripts/phase0/build_spec.py index 8b5941b62..eb4f580bd 100644 --- a/scripts/phase0/build_spec.py +++ b/scripts/phase0/build_spec.py @@ -5,8 +5,8 @@ import function_puller def build_spec(sourcefile, outfile): code_lines = [] - code_lines.append("from build.utils.minimal_ssz import *") - code_lines.append("from build.utils.bls_stub import *") + code_lines.append("from build.phase0.utils.minimal_ssz import *") + code_lines.append("from build.phase0.utils.bls_stub import *") for i in (1, 2, 3, 4, 8, 32, 48, 96): code_lines.append("def int_to_bytes%d(x): return x.to_bytes(%d, 'little')" % (i, i)) code_lines.append("SLOTS_PER_EPOCH = 64") # stub, will get overwritten by real var diff --git a/tests/phase0/conftest.py b/tests/phase0/conftest.py index 7e2800afd..7d372f164 100644 --- a/tests/phase0/conftest.py +++ b/tests/phase0/conftest.py @@ -4,7 +4,7 @@ from py_ecc import bls from build.phase0 import spec -from build.utils.merkle_minimal import ( +from build.phase0.utils.merkle_minimal import ( calc_merkle_tree_from_leaves, get_merkle_proof, get_merkle_root, diff --git a/tests/phase0/test_sanity.py b/tests/phase0/test_sanity.py index 573c3ba21..0e04df5dd 100644 --- a/tests/phase0/test_sanity.py +++ b/tests/phase0/test_sanity.py @@ -6,7 +6,7 @@ from copy import deepcopy from py_ecc import bls import build.phase0.spec as spec -from build.utils.minimal_ssz import signed_root +from build.phase0.utils.minimal_ssz import signed_root from build.phase0.spec import ( # SSZ Attestation, @@ -43,7 +43,7 @@ from build.phase0.spec import ( from build.phase0.state_transition import ( state_transition, ) -from build.utils.merkle_minimal import ( +from build.phase0.utils.merkle_minimal import ( calc_merkle_tree_from_leaves, get_merkle_proof, get_merkle_root, diff --git a/build/__init__.py b/utils/__init__.py similarity index 100% rename from build/__init__.py rename to utils/__init__.py diff --git a/build/utils/__init__.py b/utils/phase0/__init__.py similarity index 100% rename from build/utils/__init__.py rename to utils/phase0/__init__.py diff --git a/build/utils/bls_stub.py b/utils/phase0/bls_stub.py similarity index 100% rename from build/utils/bls_stub.py rename to utils/phase0/bls_stub.py diff --git a/build/utils/hash_function.py b/utils/phase0/hash_function.py similarity index 100% rename from build/utils/hash_function.py rename to utils/phase0/hash_function.py diff --git a/build/utils/merkle_minimal.py b/utils/phase0/merkle_minimal.py similarity index 100% rename from build/utils/merkle_minimal.py rename to utils/phase0/merkle_minimal.py diff --git a/build/utils/minimal_ssz.py b/utils/phase0/minimal_ssz.py similarity index 100% rename from build/utils/minimal_ssz.py rename to utils/phase0/minimal_ssz.py diff --git a/utils/phase0/state_transition.py b/utils/phase0/state_transition.py new file mode 100644 index 000000000..170f647ab --- /dev/null +++ b/utils/phase0/state_transition.py @@ -0,0 +1,100 @@ +from . import spec + + +from typing import ( + Any, + Callable, + List, + NewType, + Tuple, +) + +from .spec import ( + BeaconState, + BeaconBlock, +) + + +def process_transaction_type(state: BeaconState, + transactions: List[Any], + max_transactions: int, + tx_fn: Callable[[BeaconState, Any], None]) -> None: + assert len(transactions) <= max_transactions + for transaction in transactions: + tx_fn(state, transaction) + + +def process_transactions(state: BeaconState, block: BeaconBlock) -> None: + process_transaction_type( + state, + block.body.proposer_slashings, + spec.MAX_PROPOSER_SLASHINGS, + spec.process_proposer_slashing, + ) + process_transaction_type( + state, + block.body.attester_slashings, + spec.MAX_ATTESTER_SLASHINGS, + spec.process_attester_slashing, + ) + process_transaction_type( + state, + block.body.attestations, + spec.MAX_ATTESTATIONS, + spec.process_attestation, + ) + process_transaction_type( + state, + block.body.deposits, + spec.MAX_DEPOSITS, + spec.process_deposit, + ) + process_transaction_type( + state, + block.body.voluntary_exits, + spec.MAX_VOLUNTARY_EXITS, + spec.process_voluntary_exit, + ) + assert len(block.body.transfers) == len(set(block.body.transfers)) + process_transaction_type( + state, + block.body.transfers, + spec.MAX_TRANSFERS, + spec.process_transfer, + ) + + +def process_block(state: BeaconState, + block: BeaconBlock, + verify_state_root: bool=False) -> None: + spec.process_block_header(state, block) + spec.process_randao(state, block) + spec.process_eth1_data(state, block) + + process_transactions(state, block) + if verify_state_root: + spec.verify_block_state_root(state, block) + + +def process_epoch_transition(state: BeaconState) -> None: + spec.update_justification_and_finalization(state) + spec.process_crosslinks(state) + spec.maybe_reset_eth1_period(state) + spec.apply_rewards(state) + spec.process_ejections(state) + spec.update_registry_and_shuffling_data(state) + spec.process_slashings(state) + spec.process_exit_queue(state) + spec.finish_epoch_update(state) + + +def state_transition(state: BeaconState, + block: BeaconBlock, + verify_state_root: bool=False) -> BeaconState: + while state.slot < block.slot: + spec.cache_state(state) + if (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0: + process_epoch_transition(state) + spec.advance_slot(state) + if block.slot == state.slot: + process_block(state, block)