This is mostly a heads-up for implementers that we are moving to a new BeaconBlock format:
{
'slot': 'uint64',
'parent_root': 'hash32',
'state_root': 'hash32',
'deposit_root': 'hash32',
'randao_reveal': 'hash32',
'signature': ['uint384'],
'body': {
'proposer_slashing': [ProposerSlashingObject],
'casper_slashing': [CasperSlashingObject],
'attestations': [AttestationObject],
'deposits': [DepositObject],
'exits': [ExitObject],
},
}
Several things are going on here:
ancestor_hashes from the blocks. A historical block accumulator will go in the state instead.body for light-client friendlinessslot to signature) and the bodySuggestion:
'body_root': 'hash32' in BeaconHeader fields, where body_root is the hash of corresponding BeaconBody.BeaconHeader instead of the hash of BeaconBlock to represent the "Beacon Block Hash".I feel that will be more light-client friendly and data storing friendly.
I feel that will be more light-client friendly and data storing friendly.
Why? The tree hashing algorithm plus the header and body separation makes the data structure pretty light-client friendly.
So that the light-client can only download the headers and the certain bodys when they need?
So that the light-client can only download the headers and the certain bodys when they need?
Light clients can download the headers together with body Merkle roots. That's enough to calculate block_hash and download specific bodies trustlessly.
Clean separation of header and body, somewhat more light-client friendly
I actually don't like this :cry:
Our current approach is already very light client friendly because of how SSZ tree hashing works: if the header contains the body, then at hashing level the root of the body gets into the header as a 32 byte hash. So the status quo (plus making the body be a field of the block) is already exactly what @hwwhww is proposing :smile:
I don't think (header, body) pairs are quite as light client friendly because to chain them together you still need to dig into the header to find out what the parent is, so the end result is that clients are downloading the same structure except the formatting is more complicated.
I actually don't like this 馃槩
I agree that the header field doesn't add much, other than a bit of conceptual clarity. I'm happy with or without it.
Light clients can download the headers together with body Merkle roots.
Then the full node will need to store the body merkle roots separately for serving light client?
The easiest DB schema for full node is:
slot -> beacon_hashbeacon_hash -> BeaconBlockBut it's not ideal for serving the light clients.
If we have body_root in BeaconHeader, the DB schema in my mind will be (very similar to eth1.0):
slot -> beacon_header_hashbeacon_header_hash -> BeaconHeaderbeacon_header_hash_to_body -> BeaconBodyIf we don't have body_root in BeaconHeader, not quite sure if it's the correct solution:
slot -> beacon_block_hashbeacon_block_hash_to_header -> BeaconHeaderbeacon_block_hash_to_body -> BeaconBodybeacon_block_hash_to_body_hash -> beacon_body_hashDo we want an explicit "header contains root of body" structure, or for the header to just contain the body, as that has literally the exact same effect due to SSZ tree hashing? What are the tradeoffs here?
/cc @rawfalafel @mkalinin
Seems like the following gives us what we want as long as blocks can be served with a hash for body if requested
#### BeaconBlock
{
'slot': 'uint64',
'parent_hash': 'hash32',
'state_root': 'hash32',
'randao_reveal': 'hash32',
'candidate_pow_receipt_root': 'hash32',
'signature': ['uint384'],
'body': BeaconBlockBody,
}
blocks can be served with a hash for body if requested
If it's in this schema, the light client will need:
'slot': 'uint64',
'parent_hash': 'hash32',
'state_root': 'hash32',
'randao_reveal': 'hash32',
'candidate_pow_receipt_root': 'hash32',
'signature': ['uint384'],
If it's for light client syncing, IMO the full node won't generate/wrap the response data in runtime. So they will store the body hash in somewhere. 馃槃
/cc @zsfelfoldi
Do we want an explicit "header contains root of body" structure, or for the header to just contain the body, as that has literally the exact same effect due to SSZ tree hashing? What are the tradeoffs here?
If we want to have an option to work with chain of headers as an alternative to chain of blocks then the structure with root of body in the header is the only possible way of achieving that. Downloading chain of headers instead of blocks could potentially reduce network load since headers have small and constant size.
At the moment, it's difficult to say whether chain of headers will be important thing or not. For example, it's used by eth1.0 fast sync algorithm to verify that chain that pivot block is part of is a valid PoW chain with correct genesis. This is essential thing for the fast sync, especially when chain data is huge. AFAIR, it takes about a half of an hour to download all headers and several hours to download bodies on the main net. Chain of headers is also used by a full sync to handle forks, hence, bodies are downloaded only when header chain passes reorg safe threshold.
But these examples are from eth1.0. And it's not necessary that beacon chain sync will use same approaches as eth1.0 sync does. And in my opinion it's too early to judge on correct block/header structure at the moment, this is more about architectural and design thing that depends on how these structures will be used by a beacon chain sync.
But, if we need to make such decision now it might be useful to keep an opportunity header chains and use header structure with body root in it. It may be changed back when there will be strong understanding that we don't need such feature.
Seems like the following gives us what we want as long as blocks can be served with a hash for
bodyif requested
Won't there be collisions in case of empty bodies or bodies with same specials that seems like a possible case.
Maybe I am missing something but the only difference between this structure https://github.com/ethereum/eth2.0-specs/issues/246#issuecomment-445101678 and plain old BeaconBlock is that body have its own hash and can be requested by that hash. But what about header though? Could it be requested without a body? Header hash calculation depends on hash(body) and verifying that peer responded with requested header would only be possible when body is downloaded.
verifying that peer responded with requested header would only be possible when body is downloaded
No need to download body鈥攖he tree hash of body is sufficient.
Hm, then block header structure should be as following:
{
'slot': 'uint64',
'parent_hash': 'hash32',
'state_root': 'hash32',
'randao_reveal': 'hash32',
'candidate_pow_receipt_root': 'hash32',
'signature': ['uint384'],
'body_root': 'hash32'
}
Or there could be two version of this structure, one with body and another one with body_root.
there could be two version of this structure
At the consensus layer I don't see value in adding body_root in the header. If clients want to tack on body_root at the networking/database layer, for sure!
At the consensus layer I don't see value in adding
body_rootin theheader
Totally agree. And in terms of consensus structure described in https://github.com/ethereum/eth2.0-specs/issues/246#issuecomment-445101678 looks pretty solid to me.
@JustinDrake Do we have consensus on the historic block accumulator? I'm considering closing this issue and making a new one for the parent_hash/block accumulator
nevermind, just saw #269
With #269 merged in the only changes I'd like to see are:
parent_hash => parent_root and candidate_pow_receipt_root => deposit_rootbody fields respect the order in which the processing happens)I'll handle deposit_root and reordering fields.
Did @vbuterin push back on parent_root?
My guess is that he's sold now :) @vbuterin?
Yeah, I'm ok with parent_root.
The last point in this issue is referenced in #218 and is currently being addressed in PR #269
Most helpful comment
Totally agree. And in terms of consensus structure described in https://github.com/ethereum/eth2.0-specs/issues/246#issuecomment-445101678 looks pretty solid to me.