-
Notifications
You must be signed in to change notification settings - Fork 253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial full sync impl #117
Conversation
beacon_chain/sync_protocol.nim
Outdated
# TODO: drop this peer | ||
assert(false) | ||
|
||
let db = peer.network.protocolState(BeaconSync).db |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be peer.networkState.db
beacon_chain/sync_protocol.nim
Outdated
|
||
let blks = await p.getBlocks(node.headBlockRoot, numBlocksToDownload.int) | ||
if blks.isSome: | ||
node.applyBlocks(blks.get.blocks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice leave some placeholders for the required error handling logic here.
beacon_chain/sync_protocol.nim
Outdated
var slot = int64(blk.slot) | ||
let targetSlot = slot + step * (num - 1) | ||
while slot != targetSlot: | ||
if slot < 0 or not db.getBlock(uint64(slot), blk): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this operation looks odd - how can the database know the block of a particular slot? that requires following the fork choice, and it might change over time..
we can start without it, but what will soon happen is that we'll have a tightly coupled logic that will be hard to debug and improve, because the effect of pulling on one piece of code will be hard to analyze - ie if all the responsibilities are intertwined, with no API between them to regulate the flow of information, it's just a matter of time before the code becomes about as reliable as the nim compiler.. the idea with the design is not to remove all information flow between the layers - it's to start with the assumption that "no information should flow" and gradually weaken that to arrive at a minimal design where all information flows for a well defined reason and where the complexity price is motivated by actual benefits, rather than starting with "everything is tangled" and trying to untangle from there |
e72a1a3
to
994c787
Compare
2b4365e
to
8058079
Compare
The sync seems to work now, but it relies on the RLP serialization fix, which breaks |
f82cab3
to
bed6510
Compare
node*: BeaconNode | ||
db*: BeaconChainDB | ||
|
||
func toHeader(b: BeaconBlock): BeaconBlockHeader = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason for not using construction syntax? ie toHeader(b): .. = BeaconBlockHeader(slot: b.slot, ...)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No reason really. Somehow I keep forgetting about this option :)
Should be good to go |
beacon_chain/beacon_chain_db.nim
Outdated
array[N + 1, byte] = | ||
result[0] = byte ord(kind) | ||
result[1 .. ^1] = key | ||
func subkey[T](kind: DbKeyKind, key: T): auto = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this function a bit dangerous? I can pass a string by accident and it will do the wrong thing. Taking openarray[byte]
seems a bit safer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Added an overload instead.
beacon_chain/spec/crypto.nim
Outdated
|
||
proc append*(writer: var RlpWriter, value: ValidatorSig) = | ||
writer.append value.getBytes() | ||
|
||
proc read*(rlp: var Rlp, T: type ValidatorSig): T {.inline.} = | ||
ValidatorSig.init rlp.toBytes.toOpenArray | ||
let r = rlp.read(seq[byte]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The version using toBytes
doesn't perform an allocation. Was it wrong somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it wasn't advancing the read cursor. Fixed it differently.
bestRoot: Eth2Digest # TODO | ||
bestSlot: uint64 = node.state.data.slot | ||
|
||
await peer.status(protocolVersion, networkId, latestFinalizedRoot, latestFinalizedEpoch, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should use the new handshake
proc that gets a number of tricky details right, but I'll fix it myself in a later commit.
proc putBlock*(db: BeaconChainDB, key: Eth2Digest, value: BeaconBlock) = | ||
let slotKey = subkey(kSlotToBlockRoots, value.slot) | ||
var blockRootsBytes = db.backend.get(slotKey) | ||
var blockRoots = blockRootsBytes.toSeq(Eth2Digest) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
technically could just use ssz here no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. Just... why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for simplicity so we just have one serialization format in db (and reuse the code for flattening a seq)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I don't have a strong opinion, but a few reasons I like my approach more:
- The serialization format is localized to the beacon_db, so not a lot to keep in mind
- My format is pretty much memcpy which can easily be optimized to the least possible amount of allocations, thus more efficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was more curious than anything.. I wouldn't have bothered with coming up with a special serialization for it (and the additional unsafe code that comes with). I get the feeling the real optimization here will be to drop rocksdb
at some point.
) | ||
|
||
proc fromHeader(b: var BeaconBlock, h: BeaconBlockHeader) = | ||
b.slot = h.slot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
humm, this looks a bit dangerous in that it lets BeaconBlock.data
keep its old value.. b = BeaconBlock(...)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or ideally take both a body and a header, so it's impossible to forget to set data..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Will do.
await peer.status(protocolVersion, networkId, latestFinalizedRoot, latestFinalizedEpoch, | ||
bestRoot, bestSlot) | ||
|
||
let m = await peer.nextMsg(BeaconSync.status) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens here if peer sends something different, or doesn't send anything at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Different dispatchers will be called (e.g. getBeaconBlockHeaders
, getBeaconBlockBodies
, etc), while this coroutine will just hang forever, until the peer is disconnected, and nextMsg
eventually raises.
|
||
requestResponse: | ||
proc getBeaconBlockHeaders(peer: Peer, blockRoot: Eth2Digest, slot: uint64, maxHeaders: int, skipSlots: int) = | ||
# TODO: validate maxHeaders |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO and implement skipSlots
Some notes: