From 4f618fc62d4aefb1418f1834710669e80bd79105 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 22 Jun 2020 23:11:21 +0800 Subject: [PATCH 1/4] Rework `shard_state_transition` interface To make `shard_state_transition` similar to phase 0 `state_transition` function 1. Rename old `shard_state_transition` to `process_shard_block` 2. Add `shard_state_transition` with `validate_message` flag, we only validate it in shard fork choice --- specs/phase1/shard-fork-choice.md | 8 +++----- specs/phase1/shard-transition.md | 33 ++++++++++++++----------------- specs/phase1/validator.md | 4 ++-- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/specs/phase1/shard-fork-choice.md b/specs/phase1/shard-fork-choice.md index 411ad9b6b..1a449e3e9 100644 --- a/specs/phase1/shard-fork-choice.md +++ b/specs/phase1/shard-fork-choice.md @@ -169,14 +169,12 @@ def on_shard_block(store: Store, shard_store: ShardStore, signed_shard_block: Si ) # Check the block is valid and compute the post-state - assert verify_shard_block_message(beacon_parent_state, shard_parent_state, shard_block) - assert verify_shard_block_signature(beacon_parent_state, signed_shard_block) - - post_state = get_post_shard_state(shard_parent_state, shard_block) + shard_state = shard_parent_state.copy() + shard_state_transition(beacon_parent_state, shard_state, shard_block) # Add new block to the store shard_store.blocks[hash_tree_root(shard_block)] = shard_block # Add new state for this block to the store - shard_store.block_states[hash_tree_root(shard_block)] = post_state + shard_store.block_states[hash_tree_root(shard_block)] = shard_state ``` diff --git a/specs/phase1/shard-transition.md b/specs/phase1/shard-transition.md index 50694ce68..1433b0837 100644 --- a/specs/phase1/shard-transition.md +++ b/specs/phase1/shard-transition.md @@ -42,8 +42,6 @@ def verify_shard_block_message(beacon_parent_state: BeaconState, next_slot = Slot(block.slot + 1) offset_slots = compute_offset_slots(get_latest_slot_for_shard(beacon_parent_state, shard), next_slot) assert block.slot in offset_slots - # Check `shard` field - assert block.shard == shard # Check `proposer_index` field assert block.proposer_index == get_shard_proposer_index(beacon_parent_state, block.slot, shard) # Check `body` field @@ -63,8 +61,20 @@ def verify_shard_block_signature(beacon_state: BeaconState, ## Shard state transition ```python -def shard_state_transition(shard_state: ShardState, - block: ShardBlock) -> None: +def shard_state_transition(beacon_parent_state: BeaconState, + shard_state: ShardState, + block: ShardBlock, + validate_message: bool = True) -> bool: + if validate_message: + assert verify_shard_block_message(beacon_parent_state, shard_state, block) + + process_shard_block(shard_state, block) + return shard_state +``` + +```python +def process_shard_block(shard_state: ShardState, + block: ShardBlock) -> None: """ Update ``shard_state`` with shard ``block``. """ @@ -79,19 +89,6 @@ def shard_state_transition(shard_state: ShardState, shard_state.latest_block_root = latest_block_root ``` -We have a pure function `get_post_shard_state` for describing the fraud proof verification and honest validator behavior. - -```python -def get_post_shard_state(shard_state: ShardState, - block: ShardBlock) -> ShardState: - """ - A pure function that returns a new post ShardState instead of modifying the given `shard_state`. - """ - post_state = shard_state.copy() - shard_state_transition(post_state, block) - return post_state -``` - ## Fraud proofs ### Verifying the proof @@ -129,7 +126,7 @@ def is_valid_fraud_proof(beacon_state: BeaconState, else: shard_state = transition.shard_states[offset_index - 1] # Not doing the actual state updates here. - shard_state = get_post_shard_state(shard_state, block) + shard_state_transition(beacon_state, shard_state, block, validate_message=False) if shard_state != transition.shard_states[offset_index]: return True diff --git a/specs/phase1/validator.md b/specs/phase1/validator.md index f347f8757..39ada7891 100644 --- a/specs/phase1/validator.md +++ b/specs/phase1/validator.md @@ -286,7 +286,7 @@ def get_shard_transition_fields( shard_data_roots = [] shard_block_lengths = [] - shard_state = beacon_state.shard_states[shard] + shard_state = beacon_state.shard_states[shard].copy() shard_block_slots = [shard_block.message.slot for shard_block in shard_blocks] offset_slots = compute_offset_slots( get_latest_slot_for_shard(beacon_state, shard), @@ -299,7 +299,7 @@ def get_shard_transition_fields( else: shard_block = SignedShardBlock(message=ShardBlock(slot=slot, shard=shard)) shard_data_roots.append(Root()) - shard_state = get_post_shard_state(shard_state, shard_block.message) + shard_state_transition(beacon_state, shard_state, shard_block.message, validate_message=False) shard_states.append(shard_state) shard_block_lengths.append(len(shard_block.message.body)) From eec14424170f1afd6a3220d534dac3aa26dfebde Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 22 Jun 2020 23:41:02 +0800 Subject: [PATCH 2/4] Reorg `shard_state_transition` argument and fix `get_shard_transition_fields` --- specs/phase1/shard-fork-choice.md | 2 +- specs/phase1/shard-transition.md | 9 +++++---- specs/phase1/validator.md | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/specs/phase1/shard-fork-choice.md b/specs/phase1/shard-fork-choice.md index 1a449e3e9..b6d5c5ad4 100644 --- a/specs/phase1/shard-fork-choice.md +++ b/specs/phase1/shard-fork-choice.md @@ -170,7 +170,7 @@ def on_shard_block(store: Store, shard_store: ShardStore, signed_shard_block: Si # Check the block is valid and compute the post-state shard_state = shard_parent_state.copy() - shard_state_transition(beacon_parent_state, shard_state, shard_block) + shard_state_transition(shard_state, shard_block, validate_message=True, beacon_parent_state=beacon_parent_state) # Add new block to the store shard_store.blocks[hash_tree_root(shard_block)] = shard_block diff --git a/specs/phase1/shard-transition.md b/specs/phase1/shard-transition.md index 1433b0837..d725cd8bf 100644 --- a/specs/phase1/shard-transition.md +++ b/specs/phase1/shard-transition.md @@ -61,11 +61,12 @@ def verify_shard_block_signature(beacon_state: BeaconState, ## Shard state transition ```python -def shard_state_transition(beacon_parent_state: BeaconState, - shard_state: ShardState, +def shard_state_transition(shard_state: ShardState, block: ShardBlock, - validate_message: bool = True) -> bool: + validate_message: bool = True, + beacon_parent_state: Optional[BeaconState] = None) -> bool: if validate_message: + assert beacon_parent_state is not None assert verify_shard_block_message(beacon_parent_state, shard_state, block) process_shard_block(shard_state, block) @@ -126,7 +127,7 @@ def is_valid_fraud_proof(beacon_state: BeaconState, else: shard_state = transition.shard_states[offset_index - 1] # Not doing the actual state updates here. - shard_state_transition(beacon_state, shard_state, block, validate_message=False) + shard_state_transition(shard_state, block, validate_message=False) if shard_state != transition.shard_states[offset_index]: return True diff --git a/specs/phase1/validator.md b/specs/phase1/validator.md index 39ada7891..d78726bc2 100644 --- a/specs/phase1/validator.md +++ b/specs/phase1/validator.md @@ -280,13 +280,12 @@ def get_shard_transition_fields( beacon_state: BeaconState, shard: Shard, shard_blocks: Sequence[SignedShardBlock], - validate_signature: bool=True, ) -> Tuple[Sequence[uint64], Sequence[Root], Sequence[ShardState]]: shard_states = [] shard_data_roots = [] shard_block_lengths = [] - shard_state = beacon_state.shard_states[shard].copy() + shard_state = beacon_state.shard_states[shard] shard_block_slots = [shard_block.message.slot for shard_block in shard_blocks] offset_slots = compute_offset_slots( get_latest_slot_for_shard(beacon_state, shard), @@ -299,7 +298,8 @@ def get_shard_transition_fields( else: shard_block = SignedShardBlock(message=ShardBlock(slot=slot, shard=shard)) shard_data_roots.append(Root()) - shard_state_transition(beacon_state, shard_state, shard_block.message, validate_message=False) + shard_state = shard_state.copy() + shard_state_transition(shard_state, shard_block.message, validate_message=False) shard_states.append(shard_state) shard_block_lengths.append(len(shard_block.message.body)) From db5da9dc973c0fac9e1b9d1d3e19f755b91a8ac8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 23 Jun 2020 10:50:41 +0800 Subject: [PATCH 3/4] Fix return type Co-authored-by: Danny Ryan --- specs/phase1/shard-transition.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/phase1/shard-transition.md b/specs/phase1/shard-transition.md index d725cd8bf..e9982b370 100644 --- a/specs/phase1/shard-transition.md +++ b/specs/phase1/shard-transition.md @@ -64,7 +64,7 @@ def verify_shard_block_signature(beacon_state: BeaconState, def shard_state_transition(shard_state: ShardState, block: ShardBlock, validate_message: bool = True, - beacon_parent_state: Optional[BeaconState] = None) -> bool: + beacon_parent_state: Optional[BeaconState] = None) -> ShardState: if validate_message: assert beacon_parent_state is not None assert verify_shard_block_message(beacon_parent_state, shard_state, block) From dbd1d4e5896926109dc8244b651fbd37bab2b3e6 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 24 Jun 2020 12:14:22 +0800 Subject: [PATCH 4/4] PR feedback: Enable `verify_shard_block_signature` --- specs/phase1/shard-fork-choice.md | 4 +++- specs/phase1/shard-transition.md | 19 ++++++++++--------- specs/phase1/validator.md | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/specs/phase1/shard-fork-choice.md b/specs/phase1/shard-fork-choice.md index b6d5c5ad4..8d64eb842 100644 --- a/specs/phase1/shard-fork-choice.md +++ b/specs/phase1/shard-fork-choice.md @@ -170,7 +170,9 @@ def on_shard_block(store: Store, shard_store: ShardStore, signed_shard_block: Si # Check the block is valid and compute the post-state shard_state = shard_parent_state.copy() - shard_state_transition(shard_state, shard_block, validate_message=True, beacon_parent_state=beacon_parent_state) + shard_state_transition( + shard_state, signed_shard_block, + validate=True, beacon_parent_state=beacon_parent_state) # Add new block to the store shard_store.blocks[hash_tree_root(shard_block)] = shard_block diff --git a/specs/phase1/shard-transition.md b/specs/phase1/shard-transition.md index e9982b370..05f986000 100644 --- a/specs/phase1/shard-transition.md +++ b/specs/phase1/shard-transition.md @@ -50,10 +50,10 @@ def verify_shard_block_message(beacon_parent_state: BeaconState, ``` ```python -def verify_shard_block_signature(beacon_state: BeaconState, +def verify_shard_block_signature(beacon_parent_state: BeaconState, signed_block: SignedShardBlock) -> bool: - proposer = beacon_state.validators[signed_block.message.proposer_index] - domain = get_domain(beacon_state, DOMAIN_SHARD_PROPOSAL, compute_epoch_at_slot(signed_block.message.slot)) + proposer = beacon_parent_state.validators[signed_block.message.proposer_index] + domain = get_domain(beacon_parent_state, DOMAIN_SHARD_PROPOSAL, compute_epoch_at_slot(signed_block.message.slot)) signing_root = compute_signing_root(signed_block.message, domain) return bls.Verify(proposer.pubkey, signing_root, signed_block.signature) ``` @@ -62,14 +62,15 @@ def verify_shard_block_signature(beacon_state: BeaconState, ```python def shard_state_transition(shard_state: ShardState, - block: ShardBlock, - validate_message: bool = True, + signed_block: SignedShardBlock, + validate: bool = True, beacon_parent_state: Optional[BeaconState] = None) -> ShardState: - if validate_message: + if validate: assert beacon_parent_state is not None - assert verify_shard_block_message(beacon_parent_state, shard_state, block) + assert verify_shard_block_message(beacon_parent_state, shard_state, signed_block.message) + assert verify_shard_block_signature(beacon_parent_state, signed_block) - process_shard_block(shard_state, block) + process_shard_block(shard_state, signed_block.message) return shard_state ``` @@ -127,7 +128,7 @@ def is_valid_fraud_proof(beacon_state: BeaconState, else: shard_state = transition.shard_states[offset_index - 1] # Not doing the actual state updates here. - shard_state_transition(shard_state, block, validate_message=False) + shard_state_transition(shard_state, block, validate=False) if shard_state != transition.shard_states[offset_index]: return True diff --git a/specs/phase1/validator.md b/specs/phase1/validator.md index d78726bc2..c0d6ecbf9 100644 --- a/specs/phase1/validator.md +++ b/specs/phase1/validator.md @@ -299,7 +299,7 @@ def get_shard_transition_fields( shard_block = SignedShardBlock(message=ShardBlock(slot=slot, shard=shard)) shard_data_roots.append(Root()) shard_state = shard_state.copy() - shard_state_transition(shard_state, shard_block.message, validate_message=False) + shard_state_transition(shard_state, shard_block, validate=False) shard_states.append(shard_state) shard_block_lengths.append(len(shard_block.message.body))