Restructured shard blocks
This commit is contained in:
parent
6b1bc1e02f
commit
393436992d
|
@ -64,9 +64,31 @@ This document describes the shard transition function (data layer only) and the
|
||||||
| `MAX_GASPRICE` | `2**14` (= 16,384) | Gwei | |
|
| `MAX_GASPRICE` | `2**14` (= 16,384) | Gwei | |
|
||||||
| `GASPRICE_ADJUSTMENT_COEFFICIENT` | `2**3` (= 8) | |
|
| `GASPRICE_ADJUSTMENT_COEFFICIENT` | `2**3` (= 8) | |
|
||||||
| `DOMAIN_SHARD_LIGHT_CLIENT` | `192` | |
|
| `DOMAIN_SHARD_LIGHT_CLIENT` | `192` | |
|
||||||
|
| `DOMAIN_SHARD_PROPOSAL` | `193` | |
|
||||||
|
|
||||||
## Containers
|
## Containers
|
||||||
|
|
||||||
|
### `ShardBlockWrapper`
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ShardBlockWrapper(Container):
|
||||||
|
shard_parent_root: Hash
|
||||||
|
beacon_parent_root: Hash
|
||||||
|
slot: Slot
|
||||||
|
body: BytesN[SHARD_BLOCK_CHUNK_SIZE]
|
||||||
|
signature: BLSSignature
|
||||||
|
```
|
||||||
|
|
||||||
|
### `ShardSignedHeader`
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ShardSignedHeader(Container):
|
||||||
|
shard_parent_root: Hash
|
||||||
|
beacon_parent_root: Hash
|
||||||
|
slot: Slot
|
||||||
|
body_root: Hash
|
||||||
|
```
|
||||||
|
|
||||||
### `ShardState`
|
### `ShardState`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -104,6 +126,8 @@ class ShardTransition(Container):
|
||||||
shard_data_roots: List[List[Hash, MAX_SHARD_BLOCK_CHUNKS], MAX_SHARD_BLOCKS_PER_ATTESTATION]
|
shard_data_roots: List[List[Hash, MAX_SHARD_BLOCK_CHUNKS], MAX_SHARD_BLOCKS_PER_ATTESTATION]
|
||||||
# Intermediate state roots
|
# Intermediate state roots
|
||||||
shard_state_roots: List[ShardState, MAX_SHARD_BLOCKS_PER_ATTESTATION]
|
shard_state_roots: List[ShardState, MAX_SHARD_BLOCKS_PER_ATTESTATION]
|
||||||
|
# Proposer signature aggregate
|
||||||
|
proposer_signature_aggregate: BLSSignature
|
||||||
```
|
```
|
||||||
|
|
||||||
### `Attestation`
|
### `Attestation`
|
||||||
|
@ -322,23 +346,47 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> bool:
|
||||||
def apply_shard_transition(state: BeaconState, shard: Shard, transition: ShardTransition) -> None:
|
def apply_shard_transition(state: BeaconState, shard: Shard, transition: ShardTransition) -> None:
|
||||||
# Slot the attestation starts counting from
|
# Slot the attestation starts counting from
|
||||||
start_slot = state.shard_next_slots[shard]
|
start_slot = state.shard_next_slots[shard]
|
||||||
|
|
||||||
# Correct data root count
|
# Correct data root count
|
||||||
offset_slots = [start_slot + x for x in SHARD_BLOCK_OFFSETS if start_slot + x < state.slot]
|
offset_slots = [start_slot + x for x in SHARD_BLOCK_OFFSETS if start_slot + x < state.slot]
|
||||||
assert len(transition.shard_data_roots) == len(transition.shard_states) == len(transition.shard_block_lengths) == len(offset_slots)
|
assert len(transition.shard_data_roots) == len(transition.shard_states) == len(transition.shard_block_lengths) == len(offset_slots)
|
||||||
assert transition.start_slot == start_slot
|
assert transition.start_slot == start_slot
|
||||||
|
|
||||||
|
def chunks_to_body_root(chunks):
|
||||||
|
return hash_tree_root(chunks + [EMPTY_CHUNK_ROOT] * (MAX_SHARD_BLOCK_CHUNKS - len(chunks)))
|
||||||
|
|
||||||
|
# Reonstruct shard headers
|
||||||
|
headers = []
|
||||||
|
proposers = []
|
||||||
|
shard_parent_root = state.shard_states[shard].latest_block_hash
|
||||||
|
for i in range(len(offset_slots)):
|
||||||
|
if any(transition.shard_data_roots):
|
||||||
|
headers.append(ShardSignedHeader(
|
||||||
|
shard_parent_root=shard_parent_root
|
||||||
|
parent_hash=get_block_root_at_slot(state, state.slot-1),
|
||||||
|
slot=offset_slots[i],
|
||||||
|
body_root=chunks_to_body_root(transition.shard_data_roots[i])
|
||||||
|
))
|
||||||
|
proposers.append(get_shard_proposer(state, shard, offset_slots[i]))
|
||||||
|
shard_parent_root = hash_tree_root(headers[-1])
|
||||||
|
|
||||||
# Verify correct calculation of gas prices and slots and chunk roots
|
# Verify correct calculation of gas prices and slots and chunk roots
|
||||||
prev_gasprice = state.shard_states[shard].gasprice
|
prev_gasprice = state.shard_states[shard].gasprice
|
||||||
for i in range(len(offset_slots)):
|
for i in range(len(offset_slots)):
|
||||||
shard_state, block_length, chunks = transition.shard_states[i], transition.shard_block_lengths[i], transition.shard_data_roots[i]
|
shard_state, block_length, chunks = transition.shard_states[i], transition.shard_block_lengths[i], transition.shard_data_roots[i]
|
||||||
block_length = transition.shard
|
|
||||||
assert shard_state.gasprice == update_gasprice(prev_gasprice, block_length)
|
assert shard_state.gasprice == update_gasprice(prev_gasprice, block_length)
|
||||||
assert shard_state.slot == offset_slots[i]
|
assert shard_state.slot == offset_slots[i]
|
||||||
assert len(chunks) == block_length // SHARD_BLOCK_CHUNK_SIZE
|
assert len(chunks) == block_length // SHARD_BLOCK_CHUNK_SIZE
|
||||||
filled_roots = chunks + [EMPTY_CHUNK_ROOT] * (MAX_SHARD_BLOCK_CHUNKS - len(chunks))
|
|
||||||
assert shard_state.latest_block_hash == hash_tree_root(filled_roots)
|
|
||||||
prev_gasprice = shard_state.gasprice
|
prev_gasprice = shard_state.gasprice
|
||||||
|
|
||||||
|
# Verify combined signature
|
||||||
|
assert bls_verify_multiple(
|
||||||
|
pubkeys=[state.validators[proposer].pubkey for proposer in proposers],
|
||||||
|
message_hashes=[hash_tree_root(header) for header in headers],
|
||||||
|
signature=proposer.proposer_signature_aggregate,
|
||||||
|
domain=DOMAIN_SHARD_PROPOSAL
|
||||||
|
)
|
||||||
|
|
||||||
# Save updated state
|
# Save updated state
|
||||||
state.shard_states[shard] = transition.shard_states[-1]
|
state.shard_states[shard] = transition.shard_states[-1]
|
||||||
state.shard_states[shard].slot = state.slot - 1
|
state.shard_states[shard].slot = state.slot - 1
|
||||||
|
@ -450,29 +498,25 @@ def phase_1_epoch_transition(state):
|
||||||
|
|
||||||
### Fraud proofs
|
### Fraud proofs
|
||||||
|
|
||||||
TODO. The intent is to have a single universal fraud proof type, which contains (i) an on-time attestation on shard `s` signing a set of `data_roots`, (ii) an index `i` of a particular data root to focus on, (iii) the full contents of the i'th data, (iii) a Merkle proof to the `shard_state_roots` in the parent block the attestation is referencing, and which then verifies that one of the two conditions is false:
|
TODO. The intent is to have a single universal fraud proof type, which contains the following parts:
|
||||||
|
|
||||||
* `custody_bits[i][j] != generate_custody_bit(subkey, block_contents)` for any `j`
|
1. An on-time attestation on some `shard` signing a `ShardTransition`
|
||||||
* `execute_state_transition(shard, slot, attestation.shard_state_roots[i-1], hash_tree_root(parent), get_shard_proposer(state, shard, slot), block_contents) != shard_state_roots[i]` (if `i=0` then instead use `parent.shard_state_roots[s][-1]`)
|
2. An index `i` of a particular position to focus on
|
||||||
|
3. The `ShardTransition` itself
|
||||||
|
4. The full body of the block
|
||||||
|
5. A Merkle proof to the `shard_states` in the parent block the attestation is referencing
|
||||||
|
|
||||||
|
The proof verifies that one of the two conditions is false:
|
||||||
|
|
||||||
|
1. `custody_bits[i][j] != generate_custody_bit(subkey, block_contents)` for any `j`
|
||||||
|
2. `execute_state_transition(shard, slot, transition.shard_states[i-1].root, hash_tree_root(parent), get_shard_proposer(state, shard, slot), block_contents) != transition.shard_states[i].root` (if `i=0` then instead use `parent.shard_states[shard][-1].root`)
|
||||||
|
|
||||||
## Shard state transition function
|
## Shard state transition function
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def shard_state_transition(shard: Shard, slot: Slot, pre_state: Hash, previous_beacon_root: Hash, proposer_pubkey: BLSPubkey, block_data: BytesN[MAX_SHARD_BLOCK_CHUNKS * SHARD_BLOCK_CHUNK_SIZE]) -> Hash:
|
def shard_state_transition(shard: Shard, slot: Slot, pre_state: Hash, previous_beacon_root: Hash, proposer_pubkey: BLSPubkey, block_data: BytesN[MAX_SHARD_BLOCK_CHUNKS * SHARD_BLOCK_CHUNK_SIZE]) -> Hash:
|
||||||
# Beginning of block data is the previous block hash
|
|
||||||
assert block_data[:32] == pre_state.latest_block_hash
|
|
||||||
assert block_data[32:64] == int_to_bytes8(slot) + b'\x00' * 24
|
|
||||||
# Signature check
|
|
||||||
assert len(block_data) >= 160
|
|
||||||
assert bls_verify(
|
|
||||||
pubkey=proposer_pubkey,
|
|
||||||
message_hash=hash_tree_root(block_data[:-96]),
|
|
||||||
signature=block_data[-96:],
|
|
||||||
domain=DOMAIN_SHARD_PROPOSER
|
|
||||||
)
|
|
||||||
# We will add something more substantive in phase 2
|
# We will add something more substantive in phase 2
|
||||||
length = len(block_data.rstrip(b'\x00'))
|
return hash(pre_state + hash_tree_root(previous_beacon_root) + hash_tree_root(block_data))
|
||||||
return ShardState(slot=slot, root=hash(pre_state + hash_tree_root(block_data)), gasprice=update_gasprice(pre_state, length), latest_block_hash = hash(block_data))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Honest committee member behavior
|
## Honest committee member behavior
|
||||||
|
|
Loading…
Reference in New Issue