From 18409a69e155ae8510fc2a845979e59b3daa31fa Mon Sep 17 00:00:00 2001 From: Eugene Kabanov Date: Wed, 30 Oct 2024 07:38:53 +0200 Subject: [PATCH] Light forward sync mechanism (#6515) * Initial commit. * Add hybrid syncing. * Compilation fixes. * Cast custom event for our purposes. * Instantiate AsyncEventQueue properly. * Fix mistype. * Further research on optimistic updates. * Fixing circular deps. * Add backfilling. * Add block download feature. * Add block store. * Update backfill information before storing block. * Use custom block verifier for backfilling sync. * Skip signature verification in backfilling. * Add one more generic reload to storeBackfillBlock(). * Add block verification debugging statements. * Add more debugging * Do not use database for backfilling, part 1. * Fix for stash. * Stash fixes part 2. * Prepare for testing. * Fix assertion. * Fix post-restart syncing process. * Update backfill loading log statement. Use proper backfill slot callback for sync manager. * Add handling of Duplicates. * Fix store duration and block backfilled log statements. * Add proper syncing state log statement. * Add snappy compression to beaconchain_file. Format syncing speed properly. * Add blobs verification. * Add `slot` number to file structure for easy navigation over stream of compressed objects. * Change database filename. * Fix structure size. * Add more consistency properties. * Fix checkRepair() issues. * Preparation to state rebuild process. * Add plain & compressed size. * Debugging snappy encode process. * Add one more debugging line. * Dump blocks. * One more filedump. * Fix chunk corruption code. * Fix detection issue. * Some fixes in state rebuilding process. * Add more clearance steps. * Move updateHead() back to block_processor. * Fix compilation issues. * Make code more async friendly. * Fix async issues. Add more information when proposer verification failed. * Fix 8192 slots issue. * Fix Future double completion issue. * Pass updateFlags to some of the core procedures. * Fix tests. * Improve initial sync handling mechanism. * Fix checkStateTransition() performance improvements. * Add some performance tuning and meters. * Light client performance tuning. * Remove debugging statement. * Use single file descriptor for blockchain file. * Attempt to fix LC. * Fix timeleft calculation when untrusted sync backfilling started right after LC block received. * Workaround for `chronicles` + `results` `error` issue. Remove some compilation warnings. Fix `CatchableError` leaks on Windows. * Address review comments. * Address review comments part 2. * Address review comments part 1. * Rebase and fix the issues. * Address review comments part 3. * Add tests and fix some issues in auto-repair mechanism. * Add tests to all_tests. * Rename binary test file to pass restrictions. * Add `bin` extension to excluded list. Recover binary test data. * Rename fixture file to .bin again. * Update AllTests. * Address review comments part 4. * Address review comments part 5 and fix tests. * Address review comments part 6. * Eliminate foldl and combine from blobs processing. Add some tests to ensure that checkResponse() also checks for correct order. * Fix forgotten place. * Post rebase fixes. * Add unique slots tests. * Optimize updateHead() code. * Add forgotten changes. * Address review comments on state as argument. --- .github/workflows/ci.yml | 2 +- AllTests-mainnet.md | 11 +- beacon_chain/beacon_chain_file.nim | 950 ++++++++++++++++++ beacon_chain/beacon_node.nim | 13 +- beacon_chain/beacon_node_light_client.nim | 15 +- .../block_clearance.nim | 133 ++- .../block_pools_types.nim | 13 +- .../consensus_object_pools/blockchain_dag.nim | 44 +- .../blockchain_dag_light_client.nim | 2 +- .../blockchain_list.nim | 247 +++++ .../gossip_processing/block_processor.nim | 22 +- beacon_chain/nimbus_beacon_node.nim | 165 ++- beacon_chain/rpc/rest_rewards_api.nim | 4 +- beacon_chain/rpc/rest_utils.nim | 3 +- beacon_chain/spec/signatures_batch.nim | 32 + beacon_chain/sync/sync_manager.nim | 230 ++++- beacon_chain/sync/sync_overseer.nim | 501 +++++++++ beacon_chain/sync/sync_types.nim | 85 ++ beacon_chain/validators/validator_monitor.nim | 1 + ncli/ncli_db.nim | 15 +- research/block_sim.nim | 4 +- tests/all_tests.nim | 5 +- .../test_fixture_fork_choice.nim | 3 +- tests/fixtures/bfdata-test.bin | Bin 0 -> 292527 bytes tests/test_beacon_chain_file.nim | 342 +++++++ tests/test_block_processor.nim | 3 +- tests/test_blockchain_dag.nim | 19 +- tests/test_sync_manager.nim | 50 +- 28 files changed, 2737 insertions(+), 177 deletions(-) create mode 100644 beacon_chain/beacon_chain_file.nim create mode 100644 beacon_chain/consensus_object_pools/blockchain_list.nim create mode 100644 beacon_chain/sync/sync_overseer.nim create mode 100644 beacon_chain/sync/sync_types.nim create mode 100644 tests/fixtures/bfdata-test.bin create mode 100644 tests/test_beacon_chain_file.nim diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7661fdc52..5ad7a4370 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -254,7 +254,7 @@ jobs: if: ${{ !cancelled() }} && github.event_name == 'pull_request' run: | excluded_files="config.yaml" - excluded_extensions="ans|cfg|json|json\\.template|md|png|service|ssz|txt|lock|nix" + excluded_extensions="ans|bin|cfg|json|json\\.template|md|png|service|ssz|txt|lock|nix" current_year=$(date +"%Y") problematic_files=() diff --git a/AllTests-mainnet.md b/AllTests-mainnet.md index 3bd967ca2..f072155b3 100644 --- a/AllTests-mainnet.md +++ b/AllTests-mainnet.md @@ -70,6 +70,15 @@ OK: 4/4 Fail: 0/4 Skip: 0/4 + sanity check state diff roundtrip [Preset: mainnet] OK ``` OK: 29/29 Fail: 0/29 Skip: 0/29 +## Beacon chain file test suite +```diff ++ Auto check/repair test (missing data) OK ++ Auto check/repair test (missing footer) OK ++ Auto check/repair test (missing last chunk) OK ++ Auto check/repair test (only header) OK ++ Fixture file validation OK +``` +OK: 5/5 Fail: 0/5 Skip: 0/5 ## Beacon state [Preset: mainnet] ```diff + Smoke test initialize_beacon_state_from_eth1 [Preset: mainnet] OK @@ -1128,4 +1137,4 @@ OK: 2/2 Fail: 0/2 Skip: 0/2 OK: 9/9 Fail: 0/9 Skip: 0/9 ---TOTAL--- -OK: 765/770 Fail: 0/770 Skip: 5/770 +OK: 770/775 Fail: 0/775 Skip: 5/775 diff --git a/beacon_chain/beacon_chain_file.nim b/beacon_chain/beacon_chain_file.nim new file mode 100644 index 000000000..4333c89d0 --- /dev/null +++ b/beacon_chain/beacon_chain_file.nim @@ -0,0 +1,950 @@ +# beacon_chain +# Copyright (c) 2018-2024 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import results, snappy, stew/[io2, endians2] +import ./spec/[eth2_ssz_serialization, eth2_merkleization, forks] +from ./consensus_object_pools/block_pools_types import BlockData +export results + +type + ChainFileHeader* = object + header: uint32 + version: uint32 + kind: uint64 + comprSize: uint32 + plainSize: uint32 + slot: uint64 + + ChainFileFooter* = object + kind: uint64 + comprSize: uint32 + plainSize: uint32 + slot: uint64 + + Chunk = object + header: ChainFileHeader + footer: ChainFileFooter + data: seq[byte] + + ChainFileData* = object + head*: Opt[BlockData] + tail*: Opt[BlockData] + + ChainFileHandle* = object + data*: ChainFileData + handle*: IoHandle + + ChainFileErrorType* {.pure.} = enum + IoError, # OS input/output error + IncorrectSize, # Incorrect/unexpected size of chunk + IncompleteFooter, # Incomplete footer was read + IncompleteHeader, # Incomplete header was read + IncompleteData, # Incomplete data was read + FooterError, # Incorrect chunk's footer + HeaderError, # Incorrect chunk's header + MismatchError # Header and footer not from same chunk + + ChainFileCheckResult* {.pure.} = enum + FileMissing, + FileEmpty, + FileOk, + FileRepaired, + FileCorrupted + + ChainFileFlag* {.pure.} = enum + Repair, + OpenAlways + + ChainFileError* = object + kind*: ChainFileErrorType + message*: string + +const + ChainFileHeaderSize* = 32 + ChainFileFooterSize* = 24 + ChainFileVersion = 1'u32 + ChainFileHeaderValue = 0x424D494E'u32 + ChainFileBufferSize* = 4096 + MaxChunkSize = int(GOSSIP_MAX_SIZE) + ChainFileHeaderArray = ChainFileHeaderValue.toBytesLE() + IncompleteWriteError = "Unable to write data to file, disk full?" + MaxForksCount* = 16384 + BlockForkCodeRange = + int(ConsensusFork.Phase0) .. int(high(ConsensusFork)) + BlobForkCodeRange = + MaxForksCount .. (MaxForksCount + int(high(ConsensusFork)) - int(ConsensusFork.Deneb)) + +func getBlockForkCode(fork: ConsensusFork): uint64 = + uint64(fork) + +func getBlobForkCode(fork: ConsensusFork): uint64 = + case fork + of ConsensusFork.Deneb: + uint64(MaxForksCount) + of ConsensusFork.Electra: + uint64(MaxForksCount) + uint64(fork) - uint64(ConsensusFork.Deneb) + of ConsensusFork.Phase0 .. ConsensusFork.Capella: + raiseAssert "Blobs are not supported for the fork" + +proc init(t: typedesc[ChainFileError], k: ChainFileErrorType, + m: string): ChainFileError = + ChainFileError(kind: k, message: m) + +template init(t: typedesc[ChainFileHeader], + kind: uint64, clength, plength: uint32, + number: uint64): ChainFileHeader = + ChainFileHeader( + header: ChainFileHeaderValue, + version: ChainFileVersion, + kind: kind, + comprSize: clength, + plainSize: plength, + slot: number) + +template init(t: typedesc[ChainFileFooter], + kind: uint64, clength, plength: uint32, + number: uint64): ChainFileFooter = + ChainFileFooter( + kind: kind, + comprSize: clength, + plainSize: plength, + slot: number) + +template unmaskKind(k: uint64): uint64 = + k and not(0x8000_0000_0000_0000'u64) + +template maskKind(k: uint64): uint64 = + k or 0x8000_0000_0000_0000'u64 + +template isLast(k: uint64): bool = + (k and 0x8000_0000_0000_0000'u64) != 0'u64 + +proc checkKind(kind: uint64): Result[void, string] = + let hkind = + block: + let res = unmaskKind(kind) + if res > uint64(high(int)): + return err("Unsuppoted chunk kind value") + int(res) + if (hkind in BlockForkCodeRange) or (hkind in BlobForkCodeRange): + ok() + else: + err("Unsuppoted chunk kind value") + +proc check(a: ChainFileHeader): Result[void, string] = + if a.header != ChainFileHeaderValue: + return err("Incorrect chunk header [NIMB]") + if a.version != ChainFileVersion: + return err("Unsuppoted chunk version") + if a.comprSize > uint32(MaxChunkSize): + return err("Incorrect compressed size in chunk header") + if a.plainSize > uint32(MaxChunkSize): + return err("Incorrect plain size in chunk header") + ? checkKind(a.kind) + ok() + +proc check(a: ChainFileFooter): Result[void, string] = + if a.comprSize > uint32(MaxChunkSize): + return err("Incorrect compressed size in chunk header") + if a.plainSize > uint32(MaxChunkSize): + return err("Incorrect plain size in chunk header") + ? a.kind.checkKind() + ok() + +proc check(a: ChainFileFooter, b: ChainFileHeader): Result[void, string] = + if a.kind != b.kind: + return err("Footer and header reports different chunk kind") + if a.comprSize != b.comprSize: + return err("Footer and header reports different compressed size") + if a.plainSize != b.plainSize: + return err("Footer and header reports different plain size") + if a.slot != b.slot: + return err("Footer and header reports different slots") + ok() + +proc init(t: typedesc[ChainFileHeader], + data: openArray[byte]): Result[ChainFileHeader, string] = + doAssert(len(data) >= ChainFileHeaderSize) + let header = + ChainFileHeader( + header: uint32.fromBytesLE(data.toOpenArray(0, 3)), + version: uint32.fromBytesLE(data.toOpenArray(4, 7)), + kind: uint64.fromBytesLE(data.toOpenArray(8, 15)), + comprSize: uint32.fromBytesLE(data.toOpenArray(16, 19)), + plainSize: uint32.fromBytesLE(data.toOpenArray(20, 23)), + slot: uint64.fromBytesLE(data.toOpenArray(24, 31))) + ? check(header) + ok(header) + +proc init(t: typedesc[ChainFileFooter], + data: openArray[byte]): Result[ChainFileFooter, string] = + doAssert(len(data) >= ChainFileFooterSize) + let footer = + ChainFileFooter( + kind: uint64.fromBytesLE(data.toOpenArray(0, 7)), + comprSize: uint32.fromBytesLE(data.toOpenArray(8, 11)), + plainSize: uint32.fromBytesLE(data.toOpenArray(12, 15)), + slot: uint64.fromBytesLE(data.toOpenArray(16, 23))) + ? check(footer) + ok(footer) + +template `[]=`(data: var openArray[byte], slice: Slice[int], + src: array[4, byte]) = + var k = 0 + for i in slice: + data[i] = src[k] + inc(k) + +template `[]=`(data: var openArray[byte], slice: Slice[int], + src: array[8, byte]) = + var k = 0 + for i in slice: + data[i] = src[k] + inc(k) + +proc store(a: ChainFileHeader, data: var openArray[byte]) = + doAssert(len(data) >= ChainFileHeaderSize) + data[0 .. 3] = a.header.toBytesLE() + data[4 .. 7] = a.version.toBytesLE() + data[8 .. 15] = a.kind.toBytesLE() + data[16 .. 19] = a.comprSize.toBytesLE() + data[20 .. 23] = a.plainSize.toBytesLE() + data[24 .. 31] = a.slot.toBytesLE() + +proc store(a: ChainFileFooter, data: var openArray[byte]) = + doAssert(len(data) >= ChainFileFooterSize) + data[0 .. 7] = a.kind.toBytesLE() + data[8 .. 11] = a.comprSize.toBytesLE() + data[12 .. 15] = a.plainSize.toBytesLE() + data[16 .. 23] = a.slot.toBytesLE() + +proc init(t: typedesc[Chunk], kind, slot: uint64, plainSize: uint32, + data: openArray[byte]): seq[byte] = + doAssert((len(data) < MaxChunkSize) and (plainSize < uint32(MaxChunkSize))) + + var + dst = newSeq[byte](len(data) + ChainFileHeaderSize + ChainFileFooterSize) + + let + header = ChainFileHeader.init(kind, uint32(len(data)), plainSize, slot) + footer = ChainFileFooter.init(kind, uint32(len(data)), plainSize, slot) + + var offset = 0 + header.store(dst.toOpenArray(offset, offset + ChainFileHeaderSize - 1)) + offset += ChainFileHeaderSize + + if len(data) > 0: + copyMem(addr dst[offset], unsafeAddr data[0], len(data)) + offset += len(data) + + footer.store(dst.toOpenArray(offset, offset + ChainFileFooterSize - 1)) + dst + +template getBlockChunkKind(kind: ConsensusFork, last: bool): uint64 = + if last: + maskKind(getBlockForkCode(kind)) + else: + getBlockForkCode(kind) + +template getBlobChunkKind(kind: ConsensusFork, last: bool): uint64 = + if last: + maskKind(getBlobForkCode(kind)) + else: + getBlobForkCode(kind) + +proc getBlockConsensusFork(header: ChainFileHeader): ConsensusFork = + let hkind = unmaskKind(header.kind) + if int(hkind) in BlockForkCodeRange: + cast[ConsensusFork](hkind) + else: + raiseAssert("Should not happen") + +template isBlock(h: ChainFileHeader | ChainFileFooter): bool = + let hkind = unmaskKind(h.kind) + int(hkind) in BlockForkCodeRange + +template isBlob(h: ChainFileHeader | ChainFileFooter): bool = + let hkind = unmaskKind(h.kind) + int(hkind) in BlobForkCodeRange + +template isLast(h: ChainFileHeader | ChainFileFooter): bool = + h.kind.isLast() + +template head*(chandle: ChainFileHandle): Opt[BlockData] = + chandle.data.head + +template tail*(chandle: ChainFileHandle): Opt[BlockData] = + chandle.data.tail + +proc setHead*(chandle: var ChainFileHandle, bdata: BlockData) = + chandle.data.head = Opt.some(bdata) + +proc setTail*(chandle: var ChainFileHandle, bdata: BlockData) = + chandle.data.tail = Opt.some(bdata) + +proc store*(chandle: ChainFileHandle, signedBlock: ForkedSignedBeaconBlock, + blobs: Opt[BlobSidecars]): Result[void, string] = + let origOffset = + updateFilePos(chandle.handle, 0'i64, SeekPosition.SeekEnd).valueOr: + return err(ioErrorMsg(error)) + + block: + let + kind = getBlockChunkKind(signedBlock.kind, blobs.isNone()) + (data, plainSize) = + withBlck(signedBlock): + let res = SSZ.encode(forkyBlck) + (snappy.encode(res), len(res)) + slot = signedBlock.slot + buffer = Chunk.init(kind, uint64(slot), uint32(plainSize), data) + wrote = writeFile(chandle.handle, buffer).valueOr: + discard truncate(chandle.handle, origOffset) + discard fsync(chandle.handle) + return err(ioErrorMsg(error)) + if wrote != uint(len(buffer)): + discard truncate(chandle.handle, origOffset) + discard fsync(chandle.handle) + return err(IncompleteWriteError) + + if blobs.isSome(): + let blobSidecars = blobs.get() + for index, blob in blobSidecars.pairs(): + let + kind = + getBlobChunkKind(signedBlock.kind, (index + 1) == len(blobSidecars)) + (data, plainSize) = + block: + let res = SSZ.encode(blob[]) + (snappy.encode(res), len(res)) + slot = blob[].signed_block_header.message.slot + buffer = Chunk.init(kind, uint64(slot), uint32(plainSize), data) + + setFilePos(chandle.handle, 0'i64, SeekPosition.SeekEnd).isOkOr: + discard truncate(chandle.handle, origOffset) + discard fsync(chandle.handle) + return err(ioErrorMsg(error)) + + let + wrote = writeFile(chandle.handle, buffer).valueOr: + discard truncate(chandle.handle, origOffset) + discard fsync(chandle.handle) + return err(ioErrorMsg(error)) + if wrote != uint(len(buffer)): + discard truncate(chandle.handle, origOffset) + discard fsync(chandle.handle) + return err(IncompleteWriteError) + + fsync(chandle.handle).isOkOr: + discard truncate(chandle.handle, origOffset) + return err(ioErrorMsg(error)) + + ok() + +proc readChunkForward(handle: IoHandle, + dataRead: bool): Result[Opt[Chunk], ChainFileError] = + # This function only reads chunk header and footer, but does not read actual + # chunk data. + var + buffer = newSeq[byte](max(ChainFileHeaderSize, ChainFileFooterSize)) + data: seq[byte] + bytesRead: uint + + bytesRead = + readFile(handle, buffer.toOpenArray(0, ChainFileHeaderSize - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + if bytesRead == 0'u: + # End of file. + return ok(Opt.none(Chunk)) + + if bytesRead != uint(ChainFileHeaderSize): + return err( + ChainFileError.init(ChainFileErrorType.IncompleteHeader, + "Unable to read chunk header data, incorrect file?")) + + let + header = ChainFileHeader.init( + buffer.toOpenArray(0, ChainFileHeaderSize - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.HeaderError, error)) + + if not(dataRead): + setFilePos(handle, int64(header.comprSize), + SeekPosition.SeekCurrent).isOkOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + else: + # Safe conversion to `int`, because header.comprSize < MaxChunkSize + data.setLen(int(header.comprSize)) + bytesRead = + readFile(handle, data.toOpenArray(0, len(data) - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + if bytesRead != uint(header.comprSize): + return err( + ChainFileError.init(ChainFileErrorType.IncompleteData, + "Unable to read chunk data, incorrect file?")) + + bytesRead = + readFile(handle, buffer.toOpenArray(0, ChainFileFooterSize - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + if bytesRead != uint(ChainFileFooterSize): + return err( + ChainFileError.init(ChainFileErrorType.IncompleteFooter, + "Unable to read chunk footer data, incorrect file?")) + + let + footer = ChainFileFooter.init( + buffer.toOpenArray(0, ChainFileFooterSize - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.FooterError, error)) + + check(footer, header).isOkOr: + return err( + ChainFileError.init(ChainFileErrorType.MismatchError, error)) + + if not(dataRead): + ok(Opt.some(Chunk(header: header, footer: footer))) + else: + ok(Opt.some(Chunk(header: header, footer: footer, data: data))) + +proc readChunkBackward(handle: IoHandle, + dataRead: bool): Result[Opt[Chunk], ChainFileError] = + # This function only reads chunk header and footer, but does not read actual + # chunk data. + var + buffer = newSeq[byte](max(ChainFileHeaderSize, ChainFileFooterSize)) + data: seq[byte] + bytesRead: uint + + let offset = getFilePos(handle).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + if offset == 0: + return ok(Opt.none(Chunk)) + + if offset <= (ChainFileHeaderSize + ChainFileFooterSize): + return err( + ChainFileError.init(ChainFileErrorType.IncorrectSize, + "File position is incorrect")) + + setFilePos(handle, -ChainFileFooterSize, SeekPosition.SeekCurrent).isOkOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + bytesRead = + readFile(handle, buffer.toOpenArray(0, ChainFileFooterSize - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + if bytesRead != ChainFileFooterSize: + return err( + ChainFileError.init(ChainFileErrorType.IncompleteFooter, + "Unable to read chunk footer data, incorrect file?")) + let + footer = ChainFileFooter.init( + buffer.toOpenArray(0, ChainFileFooterSize - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.FooterError, error)) + + block: + let position = + -(ChainFileHeaderSize + ChainFileFooterSize + int64(footer.comprSize)) + setFilePos(handle, position, SeekPosition.SeekCurrent).isOkOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + bytesRead = + readFile(handle, buffer.toOpenArray(0, ChainFileHeaderSize - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + if bytesRead != ChainFileHeaderSize: + return err( + ChainFileError.init(ChainFileErrorType.IncompleteHeader, + "Unable to read chunk header data, incorrect file?")) + + let + header = ChainFileHeader.init( + buffer.toOpenArray(0, ChainFileHeaderSize - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.HeaderError, error)) + + check(footer, header).isOkOr: + return err( + ChainFileError.init(ChainFileErrorType.MismatchError, error)) + + if not(dataRead): + let position = int64(-ChainFileHeaderSize) + setFilePos(handle, position, SeekPosition.SeekCurrent).isOkOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + else: + # Safe conversion to `int`, because header.comprSize < MaxChunkSize + data.setLen(int(header.comprSize)) + bytesRead = + readFile(handle, data.toOpenArray(0, len(data) - 1)).valueOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + if bytesRead != uint(header.comprSize): + return err( + ChainFileError.init(ChainFileErrorType.IncompleteData, + "Unable to read chunk data, incorrect file?")) + + let position = -(ChainFileHeaderSize + int64(header.comprSize)) + setFilePos(handle, position, SeekPosition.SeekCurrent).isOkOr: + return err( + ChainFileError.init(ChainFileErrorType.IoError, ioErrorMsg(error))) + + if not(dataRead): + ok(Opt.some(Chunk(header: header, footer: footer))) + else: + ok(Opt.some(Chunk(header: header, footer: footer, data: data))) + +proc decodeBlock( + header: ChainFileHeader, + data: openArray[byte] +): Result[ForkedSignedBeaconBlock, string] = + if header.plainSize > uint32(MaxChunkSize): + return err("Size of block is enormously big") + + let + fork = header.getBlockConsensusFork() + decompressed = snappy.decode(data, uint32(header.plainSize)) + blck = + try: + withConsensusFork(fork): + ForkedSignedBeaconBlock.init( + SSZ.decode(decompressed, consensusFork.SignedBeaconBlock)) + except SerializationError: + return err("Incorrect block format") + ok(blck) + +proc decodeBlob( + header: ChainFileHeader, + data: openArray[byte] +): Result[BlobSidecar, string] = + if header.plainSize > uint32(MaxChunkSize): + return err("Size of blob is enormously big") + + let + decompressed = snappy.decode(data, uint32(header.plainSize)) + blob = + try: + SSZ.decode(decompressed, BlobSidecar) + except SerializationError: + return err("Incorrect blob format") + ok(blob) + +proc getChainFileTail*(handle: IoHandle): Result[Opt[BlockData], string] = + var sidecars: BlobSidecars + while true: + let chunk = + block: + let res = readChunkBackward(handle, true).valueOr: + return err(error.message) + if res.isNone(): + if len(sidecars) == 0: + return ok(Opt.none(BlockData)) + else: + return err("Blobs without block encountered, incorrect file?") + res.get() + if chunk.header.isBlob(): + let blob = ? decodeBlob(chunk.header, chunk.data) + sidecars.add(newClone blob) + else: + let blck = ? decodeBlock(chunk.header, chunk.data) + return + if len(sidecars) == 0: + ok(Opt.some(BlockData(blck: blck))) + else: + ok(Opt.some(BlockData(blck: blck, blob: Opt.some(sidecars)))) + +proc getChainFileHead*(handle: IoHandle): Result[Opt[BlockData], string] = + var + offset: int64 = 0 + endOfFile = false + + let + blck = + block: + let chunk = + block: + let res = readChunkForward(handle, true).valueOr: + return err(error.message) + if res.isNone(): + return ok(Opt.none(BlockData)) + res.get() + if not(chunk.header.isBlock()): + return err("Unexpected blob chunk encountered") + ? decodeBlock(chunk.header, chunk.data) + blob = + block: + var sidecars: BlobSidecars + block mainLoop: + while true: + offset = getFilePos(handle).valueOr: + return err(ioErrorMsg(error)) + let chunk = + block: + let res = readChunkForward(handle, true).valueOr: + return err(error.message) + if res.isNone(): + endOfFile = true + break mainLoop + res.get() + if chunk.header.isBlob(): + let blob = ? decodeBlob(chunk.header, chunk.data) + sidecars.add(newClone blob) + else: + break mainLoop + + if len(sidecars) > 0: + Opt.some(sidecars) + else: + Opt.none(BlobSidecars) + + if not(endOfFile): + setFilePos(handle, offset, SeekPosition.SeekBegin).isOkOr: + return err(ioErrorMsg(error)) + + ok(Opt.some(BlockData(blck: blck, blob: blob))) + +proc seekForSlotBackward*(handle: IoHandle, + slot: Slot): Result[Opt[int64], string] = + ## Search from the beginning of the file for the first chunk of data + ## identified by slot ``slot``. + ## This procedure updates current file position to the beginning of the found + ## chunk and returns this position as the result. + block: + let res = setFilePos(handle, 0, SeekPosition.SeekEnd) + if res.isErr(): + return err(ioErrorMsg(res.error)) + + while true: + let chunk = + block: + let res = readChunkBackward(handle, false).valueOr: + return err(error.message) + if res.isNone(): + return ok(Opt.none(int64)) + res.get() + + if chunk.header.slot == slot: + block: + let + position = + ChainFileHeaderSize + ChainFileFooterSize + + int64(chunk.header.comprSize) + res = setFilePos(handle, position, SeekPosition.SeekCurrent) + if res.isErr(): + return err(ioErrorMsg(res.error)) + block: + let res = getFilePos(handle) + if res.isErr(): + return err(ioErrorMsg(res.error)) + return ok(Opt.some(res.get())) + +proc seekForSlotForward*(handle: IoHandle, + slot: Slot): Result[Opt[int64], string] = + ## Search from the end of the file for the last chunk of data identified by + ## slot ``slot``. + ## This procedure updates current file position to the beginning of the found + ## chunk and returns this position as the result. + block: + let res = setFilePos(handle, 0, SeekPosition.SeekBegin) + if res.isErr(): + return err(ioErrorMsg(res.error)) + + while true: + let chunk = + block: + let res = readChunkForward(handle, false).valueOr: + return err(error.message) + if res.isNone(): + return ok(Opt.none(int64)) + res.get() + + if chunk.header.slot == slot: + block: + let + position = + -(ChainFileHeaderSize + ChainFileFooterSize + + int64(chunk.header.comprSize)) + res = setFilePos(handle, position, SeekPosition.SeekCurrent) + if res.isErr(): + return err(ioErrorMsg(res.error)) + block: + let res = getFilePos(handle) + if res.isErr(): + return err(ioErrorMsg(res.error)) + return ok(Opt.some(res.get())) + +proc search(data: openArray[byte], srch: openArray[byte], + state: var int): Opt[int] = + doAssert(len(srch) > 0) + for index in countdown(len(data) - 1, 0): + if data[index] == srch[len(srch) - 1 - state]: + inc(state) + if state == len(srch): + return Opt.some(index) + else: + state = 0 + Opt.none(int) + +proc seekForChunkBackward( + handle: IoHandle, + bufferSize = ChainFileBufferSize +): Result[Opt[int64], string] = + var + state = 0 + data = newSeq[byte](bufferSize) + bytesRead: uint = 0 + + while true: + let + position = getFilePos(handle).valueOr: + return err(ioErrorMsg(error)) + offset = max(0'i64, position - int64(bufferSize)) + + setFilePos(handle, offset, SeekPosition.SeekBegin).isOkOr: + return err(ioErrorMsg(error)) + + bytesRead = readFile(handle, data).valueOr: + return err(ioErrorMsg(error)) + + let indexOpt = search(data.toOpenArray(0, int(bytesRead) - 1), + ChainFileHeaderArray, state) + + if indexOpt.isNone(): + setFilePos(handle, offset, SeekPosition.SeekBegin).isOkOr: + return err(ioErrorMsg(error)) + continue + + state = 0 + + let + chunkOffset = -(int64(bytesRead) - int64(indexOpt.get())) + chunkPos = + updateFilePos(handle, chunkOffset, SeekPosition.SeekCurrent).valueOr: + return err(ioErrorMsg(error)) + chunk = readChunkForward(handle, false).valueOr: + # Incorrect chunk detected, so we start our searching again + setFilePos(handle, offset, SeekPosition.SeekBegin).isOkOr: + return err(ioErrorMsg(error)) + + if offset == 0'i64: + return ok(Opt.none(int64)) + + continue + + if chunk.isNone(): + return err("File has been changed, while repairing") + + if chunk.get().header.isLast(): + let finishOffset = getFilePos(handle).valueOr: + return err(ioErrorMsg(error)) + return ok(Opt.some(finishOffset)) + else: + if chunkPos == 0'i64: + return ok(Opt.none(int64)) + + setFilePos(handle, chunkPos, SeekPosition.SeekBegin).isOkOr: + return err(ioErrorMsg(error)) + + ok(Opt.none(int64)) + +proc checkRepair*(filename: string, + repair: bool): Result[ChainFileCheckResult, string] = + if not(isFile(filename)): + return ok(ChainFileCheckResult.FileMissing) + + let + handle = openFile(filename, {OpenFlags.Read, OpenFlags.Write}).valueOr: + return err(ioErrorMsg(error)) + filesize = getFileSize(handle).valueOr: + discard closeFile(handle) + return err(ioErrorMsg(error)) + + if filesize == 0'i64: + closeFile(handle).isOkOr: + return err(ioErrorMsg(error)) + return ok(ChainFileCheckResult.FileEmpty) + + setFilePos(handle, 0'i64, SeekPosition.SeekEnd).isOkOr: + discard closeFile(handle) + return err(ioErrorMsg(error)) + + let res = readChunkBackward(handle, false) + if res.isOk(): + let chunk = res.get() + if chunk.isNone(): + discard closeFile(handle) + return err("File was changed while reading") + + if chunk.get().header.isLast(): + # Last chunk being marked as last, everything is fine. + closeFile(handle).isOkOr: + return err(ioErrorMsg(error)) + return ok(ChainFileCheckResult.FileOk) + + # Last chunk was not marked properly, searching for the proper last chunk. + while true: + let nres = readChunkBackward(handle, false) + if nres.isErr(): + discard closeFile(handle) + return err(nres.error.message) + + let cres = nres.get() + if cres.isNone(): + # We reached start of file. + return + if repair: + truncate(handle, 0).isOkOr: + discard closeFile(handle) + return err(ioErrorMsg(error)) + closeFile(handle).isOkOr: + return err(ioErrorMsg(error)) + ok(ChainFileCheckResult.FileRepaired) + else: + closeFile(handle).isOkOr: + return err(ioErrorMsg(error)) + ok(ChainFileCheckResult.FileCorrupted) + + if cres.get().header.isLast(): + return + if repair: + let + position = getFilePos(handle).valueOr: + discard closeFile(handle) + return err(ioErrorMsg(error)) + offset = position + int64(cres.get().header.comprSize) + + ChainFileHeaderSize + ChainFileFooterSize + truncate(handle, offset).isOkOr: + discard closeFile(handle) + return err(ioErrorMsg(error)) + + closeFile(handle).isOkOr: + return err(ioErrorMsg(error)) + + ok(ChainFileCheckResult.FileRepaired) + else: + closeFile(handle).isOkOr: + return err(ioErrorMsg(error)) + ok(ChainFileCheckResult.FileCorrupted) + + ok(ChainFileCheckResult.FileCorrupted) + else: + setFilePos(handle, 0'i64, SeekPosition.SeekEnd).isOkOr: + discard closeFile(handle) + return err(ioErrorMsg(error)) + + let position = seekForChunkBackward(handle).valueOr: + discard closeFile(handle) + return err(error) + + if repair: + let newsize = + if position.isNone(): + 0'i64 + else: + position.get() + truncate(handle, newsize).isOkOr: + discard closeFile(handle) + return err(ioErrorMsg(error)) + closeFile(handle).isOkOr: + return err(ioErrorMsg(error)) + ok(ChainFileCheckResult.FileRepaired) + else: + closeFile(handle).isOkOr: + return err(ioErrorMsg(error)) + ok(ChainFileCheckResult.FileCorrupted) + +proc init*(t: typedesc[ChainFileHandle], filename: string, + flags: set[ChainFileFlag]): Result[ChainFileHandle, string] = + let + handle = + if not(isFile(filename)): + if ChainFileFlag.OpenAlways in flags: + let flags = {OpenFlags.Read, OpenFlags.Write, OpenFlags.Create} + openFile(filename, flags).valueOr: + return err(ioErrorMsg(error)) + else: + return err("File not found") + else: + # If file exists we perform automatic check/repair procedure. + let res = + checkRepair(filename, ChainFileFlag.Repair in flags).valueOr: + return err(error) + + if res notin {ChainFileCheckResult.FileMissing, FileEmpty, + FileOk, FileRepaired}: + return err("Chain file data is corrupted") + + let flags = {OpenFlags.Read, OpenFlags.Write} + openFile(filename, flags).valueOr: + return err(ioErrorMsg(error)) + + head = getChainFileHead(handle).valueOr: + discard closeFile(handle) + return err(error) + + setFilePos(handle, 0'i64, SeekPosition.SeekEnd).isOkOr: + discard closeFile(handle) + return err(ioErrorMsg(error)) + + let tail = getChainFileTail(handle).valueOr: + discard closeFile(handle) + return err(error) + + ok(ChainFileHandle(handle: handle, + data: ChainFileData(head: head, tail: tail))) + +proc close*(ch: ChainFileHandle): Result[void, string] = + closeFile(ch.handle).isOkOr: + return err(ioErrorMsg(error)) + ok() + +proc seekForSlot*(ch: ChainFileHandle, + slot: Slot): Result[Opt[int64], string] = + if ch.head.isNone() or ch.tail.isNone(): + return err("Attempt to seek for slot in empty file") + + let + headRange = + block: + let headSlot = ch.head.get().blck.slot() + if headSlot >= slot: + headSlot - slot + else: + slot - headSlot + tailRange = + block: + let tailSlot = ch.tail.get().blck.slot() + if tailSlot >= slot: + tailSlot - slot + else: + slot - tailSlot + offset = + if headRange <= tailRange: + ? seekForSlotForward(ch.handle, slot) + else: + ? seekForSlotBackward(ch.handle, slot) + ok(offset) + +proc clearFile*(filename: string): Result[void, string] = + removeFile(filename).isOkOr: + return err(ioErrorMsg(error)) + ok() diff --git a/beacon_chain/beacon_node.nim b/beacon_chain/beacon_node.nim index 94c743172..27a7c6ad3 100644 --- a/beacon_chain/beacon_node.nim +++ b/beacon_chain/beacon_node.nim @@ -22,10 +22,12 @@ import ./el/el_manager, ./consensus_object_pools/[ blockchain_dag, blob_quarantine, block_quarantine, consensus_manager, - data_column_quarantine, attestation_pool, sync_committee_msg_pool, validator_change_pool], + data_column_quarantine, attestation_pool, sync_committee_msg_pool, validator_change_pool, + blockchain_list], ./spec/datatypes/[base, altair], ./spec/eth2_apis/dynamic_fee_recipients, - ./sync/[sync_manager, request_manager], + ./spec/signatures_batch, + ./sync/[sync_manager, request_manager, sync_types], ./validators/[ action_tracker, message_router, validator_monitor, validator_pool, keystore_management], @@ -38,7 +40,7 @@ export eth2_network, el_manager, request_manager, sync_manager, eth2_processor, optimistic_processor, blockchain_dag, block_quarantine, base, message_router, validator_monitor, validator_pool, - consensus_manager, dynamic_fee_recipients + consensus_manager, dynamic_fee_recipients, sync_types type EventBus* = object @@ -57,6 +59,7 @@ type RestVersioned[ForkedLightClientFinalityUpdate]] optUpdateQueue*: AsyncEventQueue[ RestVersioned[ForkedLightClientOptimisticUpdate]] + optFinHeaderUpdateQueue*: AsyncEventQueue[ForkedLightClientHeader] BeaconNode* = ref object nickname*: string @@ -71,6 +74,7 @@ type .Raising([CancelledError]) lightClient*: LightClient dag*: ChainDAGRef + list*: ChainListRef quarantine*: ref Quarantine blobQuarantine*: ref BlobQuarantine dataColumnQuarantine*: ref DataColumnQuarantine @@ -88,8 +92,11 @@ type requestManager*: RequestManager syncManager*: SyncManager[Peer, PeerId] backfiller*: SyncManager[Peer, PeerId] + untrustedManager*: SyncManager[Peer, PeerId] + syncOverseer*: SyncOverseerRef genesisSnapshotContent*: string processor*: ref Eth2Processor + batchVerifier*: ref BatchVerifier blockProcessor*: ref BlockProcessor consensusManager*: ref ConsensusManager attachedValidatorBalanceTotal*: Gwei diff --git a/beacon_chain/beacon_node_light_client.nim b/beacon_chain/beacon_node_light_client.nim index 00efaca3b..4c1a7b653 100644 --- a/beacon_chain/beacon_node_light_client.nim +++ b/beacon_chain/beacon_node_light_client.nim @@ -53,10 +53,10 @@ proc initLightClient*( getBeaconTime, optimisticHandler) shouldInhibitSync = func(): bool = - if node.syncManager != nil: - not node.syncManager.inProgress # No LC sync needed if DAG is in sync - else: + if isNil(node.syncOverseer): false + else: + not node.syncOverseer.syncInProgress # No LC sync needed if DAG is in sync lightClient = createLightClient( node.network, rng, config, cfg, forkDigests, getBeaconTime, genesis_validators_root, LightClientFinalizationMode.Strict, @@ -107,7 +107,16 @@ proc initLightClient*( # The execution block hash is only available from Capella onward info "Ignoring new LC optimistic header until Capella" + proc onFinalizedHeader( + lightClient: LightClient, + finalizedHeader: ForkedLightClientHeader) = + if not node.consensusManager[].shouldSyncOptimistically(node.currentSlot): + return + + node.eventBus.optFinHeaderUpdateQueue.emit(finalizedHeader) + lightClient.onOptimisticHeader = onOptimisticHeader + lightClient.onFinalizedHeader = onFinalizedHeader lightClient.trustedBlockRoot = config.trustedBlockRoot elif config.trustedBlockRoot.isSome: diff --git a/beacon_chain/consensus_object_pools/block_clearance.nim b/beacon_chain/consensus_object_pools/block_clearance.nim index 89362ffd7..d43bfe56e 100644 --- a/beacon_chain/consensus_object_pools/block_clearance.nim +++ b/beacon_chain/consensus_object_pools/block_clearance.nim @@ -8,16 +8,15 @@ {.push raises: [].} import + std/sequtils, chronicles, results, stew/assign2, ../spec/[ beaconstate, forks, signatures, signatures_batch, state_transition, state_transition_epoch], - "."/[block_dag, blockchain_dag, blockchain_dag_light_client] - -from ../spec/datatypes/capella import asSigVerified, asTrusted, shortLog -from ../spec/datatypes/deneb import asSigVerified, asTrusted, shortLog + "."/[block_pools_types, block_dag, blockchain_dag, + blockchain_dag_light_client] export results, signatures_batch, block_dag, blockchain_dag @@ -114,15 +113,18 @@ proc addResolvedHeadBlock( blockRef proc checkStateTransition( - dag: ChainDAGRef, signedBlock: ForkySigVerifiedSignedBeaconBlock, - cache: var StateCache): Result[void, VerifierError] = + dag: ChainDAGRef, + signedBlock: ForkySigVerifiedSignedBeaconBlock, + cache: var StateCache, + updateFlags: UpdateFlags, +): Result[void, VerifierError] = ## Ensure block can be applied on a state func restore(v: var ForkedHashedBeaconState) = assign(dag.clearanceState, dag.headState) let res = state_transition_block( dag.cfg, dag.clearanceState, signedBlock, - cache, dag.updateFlags, restore) + cache, updateFlags, restore) if res.isErr(): info "Invalid block", @@ -150,7 +152,8 @@ proc advanceClearanceState*(dag: ChainDAGRef) = var cache = StateCache() info = ForkedEpochInfo() - dag.advanceSlots(dag.clearanceState, next, true, cache, info) + dag.advanceSlots(dag.clearanceState, next, true, cache, info, + dag.updateFlags) debug "Prepared clearance state for next block", next, updateStateDur = Moment.now() - startTick @@ -267,7 +270,7 @@ proc addHeadBlockWithParent*( # onto which we can apply the new block let clearanceBlock = BlockSlotId.init(parent.bid, signedBlock.message.slot) if not updateState( - dag, dag.clearanceState, clearanceBlock, true, cache): + dag, dag.clearanceState, clearanceBlock, true, cache, dag.updateFlags): # We should never end up here - the parent must be a block no older than and # rooted in the finalized checkpoint, hence we should always be able to # load its corresponding state @@ -297,7 +300,8 @@ proc addHeadBlockWithParent*( let sigVerifyTick = Moment.now() - ? checkStateTransition(dag, signedBlock.asSigVerified(), cache) + ? checkStateTransition(dag, signedBlock.asSigVerified(), cache, + dag.updateFlags) let stateVerifyTick = Moment.now() # Careful, clearanceState.data has been updated but not blck - we need to @@ -449,3 +453,112 @@ proc addBackfillBlock*( putBlockDur = putBlockTick - sigVerifyTick ok() + +template BlockAdded(kind: static ConsensusFork): untyped = + when kind == ConsensusFork.Electra: + OnElectraBlockAdded + elif kind == ConsensusFork.Deneb: + OnDenebBlockAdded + elif kind == ConsensusFork.Capella: + OnCapellaBlockAdded + elif kind == ConsensusFork.Bellatrix: + OnBellatrixBlockAdded + elif kind == ConsensusFork.Altair: + OnAltairBlockAdded + elif kind == ConsensusFork.Phase0: + OnPhase0BlockAdded + else: + static: raiseAssert "Unreachable" + +proc verifyBlockProposer*( + verifier: var BatchVerifier, + fork: Fork, + genesis_validators_root: Eth2Digest, + immutableValidators: openArray[ImmutableValidatorData2], + blocks: openArray[ForkedSignedBeaconBlock] +): Result[void, string] = + var sigs: seq[SignatureSet] + + ? sigs.collectProposerSignatureSet( + blocks, immutableValidators, fork, genesis_validators_root) + + if not verifier.batchVerify(sigs): + err("Block batch signature verification failed") + else: + ok() + +proc addBackfillBlockData*( + dag: ChainDAGRef, + bdata: BlockData, + onStateUpdated: OnStateUpdated, + onBlockAdded: OnForkedBlockAdded +): Result[void, VerifierError] = + var cache = StateCache() + + withBlck(bdata.blck): + let + parent = checkHeadBlock(dag, forkyBlck).valueOr: + if error == VerifierError.Duplicate: + return ok() + return err(error) + startTick = Moment.now() + parentBlock = dag.getForkedBlock(parent.bid.root).get() + trustedStateRoot = + withBlck(parentBlock): + forkyBlck.message.state_root + clearanceBlock = BlockSlotId.init(parent.bid, forkyBlck.message.slot) + updateFlags1 = dag.updateFlags + {skipLastStateRootCalculation} + + if not updateState(dag, dag.clearanceState, clearanceBlock, true, cache, + updateFlags1): + error "Unable to load clearance state for parent block, " & + "database corrupt?", clearanceBlock = shortLog(clearanceBlock) + return err(VerifierError.MissingParent) + + dag.clearanceState.setStateRoot(trustedStateRoot) + + let proposerVerifyTick = Moment.now() + + if not(isNil(onStateUpdated)): + ? onStateUpdated(forkyBlck.message.slot) + + let + stateDataTick = Moment.now() + updateFlags2 = + dag.updateFlags + {skipBlsValidation, skipStateRootValidation} + + ? checkStateTransition(dag, forkyBlck.asSigVerified(), cache, updateFlags2) + + let stateVerifyTick = Moment.now() + + if bdata.blob.isSome(): + for blob in bdata.blob.get(): + dag.db.putBlobSidecar(blob[]) + + type Trusted = typeof forkyBlck.asTrusted() + + proc onBlockAddedHandler( + blckRef: BlockRef, + trustedBlock: Trusted, + epochRef: EpochRef, + unrealized: FinalityCheckpoints + ) {.gcsafe, raises: [].} = + onBlockAdded( + blckRef, + ForkedTrustedSignedBeaconBlock.init(trustedBlock), + epochRef, + unrealized) + + let blockHandler: BlockAdded(consensusFork) = onBlockAddedHandler + + discard addResolvedHeadBlock( + dag, dag.clearanceState, + forkyBlck.asTrusted(), + true, + parent, cache, + blockHandler, + proposerVerifyTick - startTick, + stateDataTick - proposerVerifyTick, + stateVerifyTick - stateDataTick) + + ok() diff --git a/beacon_chain/consensus_object_pools/block_pools_types.nim b/beacon_chain/consensus_object_pools/block_pools_types.nim index e092b446a..78eaa1a64 100644 --- a/beacon_chain/consensus_object_pools/block_pools_types.nim +++ b/beacon_chain/consensus_object_pools/block_pools_types.nim @@ -285,7 +285,11 @@ type # balances, as used in fork choice effective_balances_bytes*: seq[byte] - OnBlockAdded[T: ForkyTrustedSignedBeaconBlock] = proc( + BlockData* = object + blck*: ForkedSignedBeaconBlock + blob*: Opt[BlobSidecars] + + OnBlockAdded*[T: ForkyTrustedSignedBeaconBlock] = proc( blckRef: BlockRef, blck: T, epochRef: EpochRef, unrealized: FinalityCheckpoints) {.gcsafe, raises: [].} OnPhase0BlockAdded* = OnBlockAdded[phase0.TrustedSignedBeaconBlock] @@ -299,6 +303,13 @@ type OnPhase0BlockAdded | OnAltairBlockAdded | OnBellatrixBlockAdded | OnCapellaBlockAdded | OnDenebBlockAdded | OnElectraBlockAdded + OnForkedBlockAdded* = proc( + blckRef: BlockRef, blck: ForkedTrustedSignedBeaconBlock, epochRef: EpochRef, + unrealized: FinalityCheckpoints) {.gcsafe, raises: [].} + + OnStateUpdated* = proc( + slot: Slot): Result[void, VerifierError] {.gcsafe, raises: [].} + HeadChangeInfoObject* = object slot*: Slot block_root* {.serializedFieldName: "block".}: Eth2Digest diff --git a/beacon_chain/consensus_object_pools/blockchain_dag.nim b/beacon_chain/consensus_object_pools/blockchain_dag.nim index bd8f7b203..7ea61a5d7 100644 --- a/beacon_chain/consensus_object_pools/blockchain_dag.nim +++ b/beacon_chain/consensus_object_pools/blockchain_dag.nim @@ -66,7 +66,8 @@ proc putBlock*( proc updateState*( dag: ChainDAGRef, state: var ForkedHashedBeaconState, bsi: BlockSlotId, - save: bool, cache: var StateCache): bool {.gcsafe.} + save: bool, cache: var StateCache, + updateFlags: UpdateFlags): bool {.gcsafe.} template withUpdatedState*( dag: ChainDAGRef, stateParam: var ForkedHashedBeaconState, @@ -77,7 +78,7 @@ template withUpdatedState*( block: let bsi {.inject.} = bsiParam var cache {.inject.} = StateCache() - if updateState(dag, stateParam, bsi, false, cache): + if updateState(dag, stateParam, bsi, false, cache, dag.updateFlags): template bid(): BlockId {.inject, used.} = bsi.bid template updatedState(): ForkedHashedBeaconState {.inject, used.} = stateParam okBody @@ -931,7 +932,8 @@ proc putState(dag: ChainDAGRef, state: ForkedHashedBeaconState, bid: BlockId) = proc advanceSlots*( dag: ChainDAGRef, state: var ForkedHashedBeaconState, slot: Slot, save: bool, - cache: var StateCache, info: var ForkedEpochInfo) = + cache: var StateCache, info: var ForkedEpochInfo, + updateFlags: UpdateFlags) = # Given a state, advance it zero or more slots by applying empty slot # processing - the state must be positioned at or before `slot` doAssert getStateField(state, slot) <= slot @@ -945,7 +947,7 @@ proc advanceSlots*( process_slots( dag.cfg, state, getStateField(state, slot) + 1, cache, info, - dag.updateFlags).expect("process_slots shouldn't fail when state slot is correct") + updateFlags).expect("process_slots shouldn't fail when state slot is correct") if save: dag.putState(state, stateBid) @@ -967,7 +969,8 @@ proc advanceSlots*( proc applyBlock( dag: ChainDAGRef, state: var ForkedHashedBeaconState, bid: BlockId, - cache: var StateCache, info: var ForkedEpochInfo): Result[void, cstring] = + cache: var StateCache, info: var ForkedEpochInfo, + updateFlags: UpdateFlags): Result[void, cstring] = loadStateCache(dag, cache, bid, getStateField(state, slot).epoch) discard case dag.cfg.consensusForkAtEpoch(bid.slot.epoch) @@ -976,37 +979,37 @@ proc applyBlock( return err("Block load failed") ? state_transition( dag.cfg, state, data, cache, info, - dag.updateFlags + {slotProcessed}, noRollback) + updateFlags + {slotProcessed}, noRollback) of ConsensusFork.Altair: let data = getBlock(dag, bid, altair.TrustedSignedBeaconBlock).valueOr: return err("Block load failed") ? state_transition( dag.cfg, state, data, cache, info, - dag.updateFlags + {slotProcessed}, noRollback) + updateFlags + {slotProcessed}, noRollback) of ConsensusFork.Bellatrix: let data = getBlock(dag, bid, bellatrix.TrustedSignedBeaconBlock).valueOr: return err("Block load failed") ? state_transition( dag.cfg, state, data, cache, info, - dag.updateFlags + {slotProcessed}, noRollback) + updateFlags + {slotProcessed}, noRollback) of ConsensusFork.Capella: let data = getBlock(dag, bid, capella.TrustedSignedBeaconBlock).valueOr: return err("Block load failed") ? state_transition( dag.cfg, state, data, cache, info, - dag.updateFlags + {slotProcessed}, noRollback) + updateFlags + {slotProcessed}, noRollback) of ConsensusFork.Deneb: let data = getBlock(dag, bid, deneb.TrustedSignedBeaconBlock).valueOr: return err("Block load failed") ? state_transition( dag.cfg, state, data, cache, info, - dag.updateFlags + {slotProcessed}, noRollback) + updateFlags + {slotProcessed}, noRollback) of ConsensusFork.Electra: let data = getBlock(dag, bid, electra.TrustedSignedBeaconBlock).valueOr: return err("Block load failed") ? state_transition( dag.cfg, state, data, cache, info, - dag.updateFlags + {slotProcessed}, noRollback) + updateFlags + {slotProcessed}, noRollback) ok() @@ -1140,7 +1143,7 @@ proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB, while headBlocks.len > 0: dag.applyBlock( dag.headState, headBlocks.pop().bid, cache, - info).expect("head blocks should apply") + info, dag.updateFlags).expect("head blocks should apply") dag.head = headRef dag.heads = @[headRef] @@ -1399,7 +1402,8 @@ proc getEpochRef*( return err("Requesting EpochRef for non-canonical block") var cache: StateCache - if not updateState(dag, dag.epochRefState, ancestor, false, cache): + if not updateState(dag, dag.epochRefState, ancestor, false, cache, + dag.updateFlags): return err("Could not load requested state") ok(dag.getEpochRef(dag.epochRefState, cache)) @@ -1685,7 +1689,7 @@ proc getBlockRange*( proc updateState*( dag: ChainDAGRef, state: var ForkedHashedBeaconState, bsi: BlockSlotId, - save: bool, cache: var StateCache): bool = + save: bool, cache: var StateCache, updateFlags: UpdateFlags): bool = ## Rewind or advance state such that it matches the given block and slot - ## this may include replaying from an earlier snapshot if blck is on a ## different branch or has advanced to a higher slot number than slot @@ -1839,7 +1843,8 @@ proc updateState*( # again. Also, because we're applying blocks that were loaded from the # database, we can skip certain checks that have already been performed # before adding the block to the database. - if (let res = dag.applyBlock(state, ancestors[i], cache, info); res.isErr): + if (let res = dag.applyBlock(state, ancestors[i], cache, info, + updateFlags); res.isErr): warn "Failed to apply block from database", blck = shortLog(ancestors[i]), state_bid = shortLog(state.latest_block_id), @@ -1848,7 +1853,7 @@ proc updateState*( return false # ...and make sure to process empty slots as requested - dag.advanceSlots(state, bsi.slot, save, cache, info) + dag.advanceSlots(state, bsi.slot, save, cache, info, updateFlags) # ...and make sure to load the state cache, if it exists loadStateCache(dag, cache, bsi.bid, getStateField(state, slot).epoch) @@ -2387,7 +2392,7 @@ proc updateHead*( # to use existing in-memory states to make this smooth var cache: StateCache if not updateState( - dag, dag.headState, newHead.bid.atSlot(), false, cache): + dag, dag.headState, newHead.bid.atSlot(), false, cache, dag.updateFlags): # Advancing the head state should never fail, given that the tail is # implicitly finalised, the head is an ancestor of the tail and we always # store the tail state in the database, as well as every epoch slot state in @@ -2651,7 +2656,7 @@ proc getProposalState*( # it now if not dag.updateState( state[], head.atSlot(slot - 1).toBlockSlotId().expect("not nil"), - false, cache): + false, cache, dag.updateFlags): error "Cannot get proposal state - skipping block production, database corrupt?", head = shortLog(head), slot @@ -2840,7 +2845,8 @@ proc rebuildIndex*(dag: ChainDAGRef) = # The slot check is needed to avoid re-applying a block if bids.isProposed and getStateField(state[], latest_block_header).slot < bids.bid.slot: - let res = dag.applyBlock(state[], bids.bid, cache, info) + let res = dag.applyBlock(state[], bids.bid, cache, info, + dag.updateFlags) if res.isErr: error "Failed to apply block while building index", state_bid = shortLog(state[].latest_block_id()), diff --git a/beacon_chain/consensus_object_pools/blockchain_dag_light_client.nim b/beacon_chain/consensus_object_pools/blockchain_dag_light_client.nim index 586449a52..8c22bd5ce 100644 --- a/beacon_chain/consensus_object_pools/blockchain_dag_light_client.nim +++ b/beacon_chain/consensus_object_pools/blockchain_dag_light_client.nim @@ -35,7 +35,7 @@ proc updateExistingState( dag: ChainDAGRef, state: var ForkedHashedBeaconState, bsi: BlockSlotId, save: bool, cache: var StateCache): bool = ## Wrapper around `updateState` for states expected to exist. - let ok = dag.updateState(state, bsi, save, cache) + let ok = dag.updateState(state, bsi, save, cache, dag.updateFlags) if not ok: error "State failed to load unexpectedly", bsi, tail = dag.tail.slot, backfill = shortLog(dag.backfill) diff --git a/beacon_chain/consensus_object_pools/blockchain_list.nim b/beacon_chain/consensus_object_pools/blockchain_list.nim new file mode 100644 index 000000000..b7677f8b0 --- /dev/null +++ b/beacon_chain/consensus_object_pools/blockchain_list.nim @@ -0,0 +1,247 @@ +# beacon_chain +# Copyright (c) 2018-2024 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import std/sequtils, stew/io2, chronicles, chronos, metrics, + ../spec/forks, + ../[beacon_chain_file, beacon_clock], + ../sszdump + +from ./block_pools_types import VerifierError, BlockData +from ../spec/state_transition_block import validate_blobs +from std/os import `/` + +export beacon_chain_file + +const + ChainFileName = "nbc.bfdata" + +type + ChainListRef* = ref object + path*: string + handle*: Opt[ChainFileHandle] + +template chainFilePath*(directory: string): string = + directory / ChainFileName + +template filePath*(clist: ChainListRef): string = + chainFilePath(clist.path) + +proc init*(T: type ChainListRef, directory: string): ChainListRef = + let + filename = directory.chainFilePath() + handle = + if not(isFile(filename)): + Opt.none(ChainFileHandle) + else: + let + flags = {ChainFileFlag.Repair} + res = ChainFileHandle.init(filename, flags) + if res.isErr(): + fatal "Unexpected failure while loading backfill data", + filename = filename, reason = res.error + quit 1 + Opt.some(res.get()) + ChainListRef(path: directory, handle: handle) + +proc init*(T: type ChainListRef, directory: string, + slot: Slot): Result[ChainListRef, string] = + let + flags = {ChainFileFlag.Repair, ChainFileFlag.OpenAlways} + filename = directory.chainFilePath() + handle = ? ChainFileHandle.init(filename, flags) + offset {.used.} = ? seekForSlot(handle, slot) + ok(ChainListRef(path: directory, handle: Opt.some(handle))) + +proc seekForSlot*(clist: ChainListRef, slot: Slot): Result[void, string] = + if clist.handle.isNone(): + let + flags = {ChainFileFlag.Repair, ChainFileFlag.OpenAlways} + filename = clist.path.chainFilePath() + handle = ? ChainFileHandle.init(filename, flags) + clist.handle = Opt.some(handle) + + let offset {.used.} = ? seekForSlot(clist.handle.get(), slot) + ok() + +proc close*(clist: ChainListRef): Result[void, string] = + if clist.handle.isNone(): + return ok() + ? clist.handle.get().close() + ok() + +proc clear*(clist: ChainListRef): Result[void, string] = + ? clist.close() + ? clearFile(clist.path.chainFilePath()) + clist.handle = Opt.none(ChainFileHandle) + ok() + +template slot*(data: BlockData): Slot = + data.blck.slot + +template parent_root*(data: ForkedSignedBeaconBlock): Eth2Digest = + withBlck(data): forkyBlck.message.parent_root + +template parent_root*(data: BlockData): Eth2Digest = + data.blck.parent_root() + +template root*(data: BlockData): Eth2Digest = + withBlck(data.blck): forkyBlck.root + +template shortLog*(x: BlockData): string = + let count = if x.blob.isSome(): $len(x.blob.get()) else: "0" + $(x.slot()) & "@" & shortLog(x.parent_root()) & "#" & count + +template shortLog*(x: Opt[BlockData]): string = + if x.isNone(): + "[none]" + else: + shortLog(x.get()) + +func tail*(clist: ChainListRef): Opt[BlockData] = + if clist.handle.isSome(): + clist.handle.get().data.tail + else: + Opt.none(BlockData) + +func head*(clist: ChainListRef): Opt[BlockData] = + if clist.handle.isSome(): + clist.handle.get().data.head + else: + Opt.none(BlockData) + +proc setHead*(clist: ChainListRef, bdata: BlockData) = + doAssert(clist.handle.isSome()) + var handle = clist.handle.get() + handle.setHead(bdata) + clist.handle = Opt.some(handle) + +proc setTail*(clist: ChainListRef, bdata: BlockData) = + doAssert(clist.handle.isSome()) + var handle = clist.handle.get() + handle.setTail(bdata) + clist.handle = Opt.some(handle) + +proc store*(clist: ChainListRef, signedBlock: ForkedSignedBeaconBlock, + blobs: Opt[BlobSidecars]): Result[void, string] = + if clist.handle.isNone(): + let + filename = clist.path.chainFilePath() + flags = {ChainFileFlag.Repair, ChainFileFlag.OpenAlways} + handle = ? ChainFileHandle.init(filename, flags) + clist.handle = Opt.some(handle) + store(handle, signedBlock, blobs) + else: + store(clist.handle.get(), signedBlock, blobs) + +proc checkBlobs(signedBlock: ForkedSignedBeaconBlock, + blobsOpt: Opt[BlobSidecars]): Result[void, VerifierError] = + withBlck(signedBlock): + when consensusFork >= ConsensusFork.Deneb: + if blobsOpt.isSome(): + let blobs = blobsOpt.get() + + template blob_kzg_commitments(): untyped = + forkyBlck.message.body.blob_kzg_commitments.asSeq + + if len(blobs) > 0: + if len(blobs) != len(blob_kzg_commitments): + return err(VerifierError.Invalid) + let res = + validate_blobs(blob_kzg_commitments, + blobs.mapIt(KzgBlob(bytes: it.blob)), + blobs.mapIt(it.kzg_proof)) + if res.isErr(): + debug "Blob validation failed", + block_root = shortLog(forkyBlck.root), + blobs = shortLog(blobs), + blck = shortLog(forkyBlck.message), + kzg_commits = mapIt(blob_kzg_commitments, shortLog(it)), + signature = shortLog(forkyBlck.signature), + msg = res.error() + return err(VerifierError.Invalid) + ok() + +proc addBackfillBlockData*( + clist: ChainListRef, signedBlock: ForkedSignedBeaconBlock, + blobsOpt: Opt[BlobSidecars]): Result[void, VerifierError] = + doAssert(not(isNil(clist))) + + logScope: + backfill_tail = shortLog(clist.tail) + signed_block_slot = signedBlock.slot + signed_block_root = signedBlock.root + signed_block_parent_root = signedBlock.parent_root + + let verifyBlockTick = Moment.now() + + if clist.tail.isNone(): + ? checkBlobs(signedBlock, blobsOpt) + + let storeBlockTick = Moment.now() + + store(clist, signedBlock, blobsOpt).isOkOr: + fatal "Unexpected failure while trying to store data", + filename = chainFilePath(clist.path), reason = error + quit 1 + + let bdata = BlockData(blck: signedBlock, blob: blobsOpt) + clist.setTail(bdata) + if clist.head.isNone(): + clist.setHead(bdata) + + debug "Initial block backfilled", + verify_block_duration = shortLog(storeBlockTick - verifyBlockTick), + store_block_duration = shortLog(Moment.now() - storeBlockTick) + + return ok() + + let tail = clist.tail.get() + + if signedBlock.slot == tail.slot: + if signedBlock.root == tail.root: + debug "Duplicate block" + return err(VerifierError.Duplicate) + else: + debug "Block from unviable fork" + return err(VerifierError.UnviableFork) + elif signedBlock.slot > tail.slot: + debug "Block from unviable fork" + return err(VerifierError.UnviableFork) + + if tail.parent_root != signedBlock.root: + debug "Block does not match expected backfill root" + return err(VerifierError.MissingParent) + + ? checkBlobs(signedBlock, blobsOpt) + + let storeBlockTick = Moment.now() + + store(clist, signedBlock, blobsOpt).isOkOr: + fatal "Unexpected failure while trying to store data", + filename = chainFilePath(clist.path), reason = error + quit 1 + + debug "Block backfilled", + verify_block_duration = shortLog(storeBlockTick - verifyBlockTick), + store_block_duration = shortLog(Moment.now() - storeBlockTick) + + clist.setTail(BlockData(blck: signedBlock, blob: blobsOpt)) + + ok() + +proc untrustedBackfillVerifier*( + clist: ChainListRef, + signedBlock: ForkedSignedBeaconBlock, + blobs: Opt[BlobSidecars], + maybeFinalized: bool +): Future[Result[void, VerifierError]] {. + async: (raises: [CancelledError], raw: true).} = + let retFuture = newFuture[Result[void, VerifierError]]() + retFuture.complete(clist.addBackfillBlockData(signedBlock, blobs)) + retFuture diff --git a/beacon_chain/gossip_processing/block_processor.nim b/beacon_chain/gossip_processing/block_processor.nim index 7fbb56fa9..a1677162f 100644 --- a/beacon_chain/gossip_processing/block_processor.nim +++ b/beacon_chain/gossip_processing/block_processor.nim @@ -107,7 +107,7 @@ type ## The slot at which we sent a payload to the execution client the last ## time - NewPayloadStatus {.pure.} = enum + NewPayloadStatus* {.pure.} = enum valid notValid invalid @@ -123,7 +123,7 @@ type proc new*(T: type BlockProcessor, dumpEnabled: bool, dumpDirInvalid, dumpDirIncoming: string, - rng: ref HmacDrbgContext, taskpool: TaskPoolPtr, + batchVerifier: ref BatchVerifier, consensusManager: ref ConsensusManager, validatorMonitor: ref ValidatorMonitor, blobQuarantine: ref BlobQuarantine, @@ -137,7 +137,7 @@ proc new*(T: type BlockProcessor, validatorMonitor: validatorMonitor, blobQuarantine: blobQuarantine, getBeaconTime: getBeaconTime, - verifier: BatchVerifier.init(rng, taskpool) + verifier: batchVerifier[] ) # Sync callbacks @@ -416,6 +416,22 @@ proc enqueueBlock*( except AsyncQueueFullError: raiseAssert "unbounded queue" +proc updateHead*( + consensusManager: ref ConsensusManager, + getBeaconTimeFn: GetBeaconTimeFn, +): Result[void, string] = + let + attestationPool = consensusManager.attestationPool + wallTime = getBeaconTimeFn() + wallSlot = wallTime.slotOrZero() + newHead = + attestationPool[].selectOptimisticHead(wallSlot.start_beacon_time) + if newHead.isOk(): + consensusManager[].updateHead(newHead.get.blck) + ok() + else: + err("Head selection failed, using previous head") + proc storeBlock( self: ref BlockProcessor, src: MsgSource, wallTime: BeaconTime, signedBlock: ForkySignedBeaconBlock, diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index bd13490a3..9c36d54d2 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -13,7 +13,8 @@ import metrics, metrics/chronos_httpserver, stew/[byteutils, io2], eth/p2p/discoveryv5/[enr, random2], - ./consensus_object_pools/[blob_quarantine, data_column_quarantine], + ./consensus_object_pools/[ + blob_quarantine, data_column_quarantine, blockchain_list], ./consensus_object_pools/vanity_logs/vanity_logs, ./networking/[topic_params, network_metadata_downloads], ./rpc/[rest_api, state_ttl_cache], @@ -21,7 +22,7 @@ import ./spec/[ deposit_snapshots, engine_authentication, weak_subjectivity, eip7594_helpers], - ./sync/[sync_protocol, light_client_protocol], + ./sync/[sync_protocol, light_client_protocol, sync_overseer], ./validators/[keystore_management, beacon_validators], "."/[ beacon_node, beacon_node_light_client, deposits, @@ -275,10 +276,19 @@ proc checkWeakSubjectivityCheckpoint( from ./spec/state_transition_block import kzg_commitment_to_versioned_hash +proc isSlotWithinWeakSubjectivityPeriod(dag: ChainDagRef, slot: Slot): bool = + let + checkpoint = Checkpoint( + epoch: epoch(getStateField(dag.headState, slot)), + root: getStateField(dag.headState, latest_block_header).state_root) + is_within_weak_subjectivity_period(dag.cfg, slot, + dag.headState, checkpoint) + proc initFullNode( node: BeaconNode, rng: ref HmacDrbgContext, dag: ChainDAGRef, + clist: ChainListRef, taskpool: TaskPoolPtr, getBeaconTime: GetBeaconTimeFn) {.async.} = template config(): auto = node.config @@ -369,17 +379,18 @@ proc initFullNode( else: dag.tail.slot + func getUntrustedBackfillSlot(): Slot = + if clist.tail.isSome(): + clist.tail.get().blck.slot + else: + dag.tail.slot + func getFrontfillSlot(): Slot = max(dag.frontfill.get(BlockId()).slot, dag.horizon) proc isWithinWeakSubjectivityPeriod(): bool = - let - currentSlot = node.beaconClock.now().slotOrZero() - checkpoint = Checkpoint( - epoch: epoch(getStateField(node.dag.headState, slot)), - root: getStateField(node.dag.headState, latest_block_header).state_root) - is_within_weak_subjectivity_period(node.dag.cfg, currentSlot, - node.dag.headState, checkpoint) + isSlotWithinWeakSubjectivityPeriod(node.dag, + node.beaconClock.now().slotOrZero()) proc eventWaiter(): Future[void] {.async: (raises: [CancelledError]).} = await node.shutdownEvent.wait() @@ -414,10 +425,12 @@ proc initFullNode( ActionTracker.init(node.network.nodeId, config.subscribeAllSubnets), node.dynamicFeeRecipientsStore, config.validatorsDir, config.defaultFeeRecipient, config.suggestedGasLimit) + batchVerifier = BatchVerifier.new(rng, taskpool) blockProcessor = BlockProcessor.new( config.dumpEnabled, config.dumpDirInvalid, config.dumpDirIncoming, - rng, taskpool, consensusManager, node.validatorMonitor, + batchVerifier, consensusManager, node.validatorMonitor, blobQuarantine, getBeaconTime) + blockVerifier = proc(signedBlock: ForkedSignedBeaconBlock, blobs: Opt[BlobSidecars], maybeFinalized: bool): Future[Result[void, VerifierError]] {.async: (raises: [CancelledError], raw: true).} = @@ -427,6 +440,11 @@ proc initFullNode( # that should probably be reimagined more holistically in the future. blockProcessor[].addBlock( MsgSource.gossip, signedBlock, blobs, maybeFinalized = maybeFinalized) + untrustedBlockVerifier = + proc(signedBlock: ForkedSignedBeaconBlock, blobs: Opt[BlobSidecars], + maybeFinalized: bool): Future[Result[void, VerifierError]] {. + async: (raises: [CancelledError], raw: true).} = + clist.untrustedBackfillVerifier(signedBlock, blobs, maybeFinalized) rmanBlockVerifier = proc(signedBlock: ForkedSignedBeaconBlock, maybeFinalized: bool): Future[Result[void, VerifierError]] {.async: (raises: [CancelledError]).} = @@ -487,6 +505,20 @@ proc initFullNode( dag.backfill.slot, blockVerifier, maxHeadAge = 0, shutdownEvent = node.shutdownEvent, flags = syncManagerFlags) + clistPivotSlot = + if clist.tail.isSome(): + clist.tail.get().blck.slot() + else: + getLocalWallSlot() + untrustedManager = newSyncManager[Peer, PeerId]( + node.network.peerPool, + dag.cfg.DENEB_FORK_EPOCH, dag.cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS, + SyncQueueKind.Backward, getLocalHeadSlot, + getLocalWallSlot, getFirstSlotAtFinalizedEpoch, getUntrustedBackfillSlot, + getFrontfillSlot, isWithinWeakSubjectivityPeriod, + clistPivotSlot, untrustedBlockVerifier, maxHeadAge = 0, + shutdownEvent = node.shutdownEvent, + flags = syncManagerFlags) router = (ref MessageRouter)( processor: processor, network: node.network) @@ -540,6 +572,7 @@ proc initFullNode( dag.setReorgCb(onChainReorg) node.dag = dag + node.list = clist node.blobQuarantine = blobQuarantine node.quarantine = quarantine node.attestationPool = attestationPool @@ -547,11 +580,24 @@ proc initFullNode( node.lightClientPool = lightClientPool node.validatorChangePool = validatorChangePool node.processor = processor + node.batchVerifier = batchVerifier node.blockProcessor = blockProcessor node.consensusManager = consensusManager node.requestManager = requestManager node.syncManager = syncManager node.backfiller = backfiller + node.untrustedManager = untrustedManager + node.syncOverseer = SyncOverseerRef.new(node.consensusManager, + node.validatorMonitor, + config, + getBeaconTime, + node.list, + node.beaconClock, + node.eventBus.optFinHeaderUpdateQueue, + node.network.peerPool, + node.batchVerifier, + syncManager, backfiller, + untrustedManager) node.router = router await node.addValidators() @@ -627,11 +673,20 @@ proc init*(T: type BeaconNode, checkpoint = Checkpoint( epoch: epoch(getStateField(genesisState[], slot)), root: getStateField(genesisState[], latest_block_header).state_root) + + notice "Genesis state information", + genesis_fork = genesisState.kind, + is_post_altair = (cfg.ALTAIR_FORK_EPOCH == GENESIS_EPOCH) + if config.longRangeSync == LongRangeSyncMode.Light: if not is_within_weak_subjectivity_period(metadata.cfg, currentSlot, genesisState[], checkpoint): - fatal WeakSubjectivityLogMessage, current_slot = currentSlot - quit 1 + # We do support any network which starts from Altair or later fork. + let metadata = config.loadEth2Network() + if metadata.cfg.ALTAIR_FORK_EPOCH != GENESIS_EPOCH: + fatal WeakSubjectivityLogMessage, current_slot = currentSlot, + altair_fork_epoch = metadata.cfg.ALTAIR_FORK_EPOCH + quit 1 try: if config.numThreads < 0: @@ -669,7 +724,8 @@ proc init*(T: type BeaconNode, finUpdateQueue: newAsyncEventQueue[ RestVersioned[ForkedLightClientFinalityUpdate]](), optUpdateQueue: newAsyncEventQueue[ - RestVersioned[ForkedLightClientOptimisticUpdate]]()) + RestVersioned[ForkedLightClientOptimisticUpdate]](), + optFinHeaderUpdateQueue: newAsyncEventQueue[ForkedLightClientHeader]()) db = BeaconChainDB.new(config.databaseDir, cfg, inMemory = false) if config.externalBeaconApiUrl.isSome and ChainDAGRef.isInitialized(db).isErr: @@ -843,6 +899,28 @@ proc init*(T: type BeaconNode, getBeaconTime = beaconClock.getBeaconTimeFn() + let clist = + block: + let res = ChainListRef.init(config.databaseDir()) + + debug "Backfill database has been loaded", path = config.databaseDir(), + head = shortLog(res.head), tail = shortLog(res.tail) + + if res.handle.isSome() and res.tail().isSome(): + if not(isSlotWithinWeakSubjectivityPeriod(dag, res.tail.get().slot())): + notice "Backfill database is outdated " & + "(outside of weak subjectivity period), reseting database", + path = config.databaseDir(), + tail = shortLog(res.tail) + res.clear().isOkOr: + fatal "Unable to reset backfill database", + path = config.databaseDir(), reason = error + quit 1 + res + + info "Backfill database initialized", path = config.databaseDir(), + head = shortLog(clist.head), tail = shortLog(clist.tail) + if config.weakSubjectivityCheckpoint.isSome: dag.checkWeakSubjectivityCheckpoint( config.weakSubjectivityCheckpoint.get, beaconClock) @@ -970,7 +1048,7 @@ proc init*(T: type BeaconNode, node.initLightClient( rng, cfg, dag.forkDigests, getBeaconTime, dag.genesis_validators_root) - await node.initFullNode(rng, dag, taskpool, getBeaconTime) + await node.initFullNode(rng, dag, clist, taskpool, getBeaconTime) node.updateLightClientFromDag() @@ -1682,26 +1760,29 @@ func formatNextConsensusFork( $nextConsensusFork & ":" & $nextForkEpoch) func syncStatus(node: BeaconNode, wallSlot: Slot): string = - let optimisticHead = not node.dag.head.executionValid - if node.syncManager.inProgress: - let - optimisticSuffix = - if optimisticHead: - "/opt" - else: - "" - lightClientSuffix = - if node.consensusManager[].shouldSyncOptimistically(wallSlot): - " - lc: " & $shortLog(node.consensusManager[].optimisticHead) - else: - "" - node.syncManager.syncStatus & optimisticSuffix & lightClientSuffix - elif node.backfiller.inProgress: - "backfill: " & node.backfiller.syncStatus - elif optimisticHead: - "synced/opt" - else: - "synced" + node.syncOverseer.statusMsg.valueOr: + let optimisticHead = not node.dag.head.executionValid + if node.syncManager.inProgress: + let + optimisticSuffix = + if optimisticHead: + "/opt" + else: + "" + lightClientSuffix = + if node.consensusManager[].shouldSyncOptimistically(wallSlot): + " - lc: " & $shortLog(node.consensusManager[].optimisticHead) + else: + "" + node.syncManager.syncStatus & optimisticSuffix & lightClientSuffix + elif node.untrustedManager.inProgress: + "untrusted: " & node.untrustedManager.syncStatus + elif node.backfiller.inProgress: + "backfill: " & node.backfiller.syncStatus + elif optimisticHead: + "synced/opt" + else: + "synced" when defined(windows): from winservice import establishWindowsService, reportServiceStatusSuccess @@ -1995,18 +2076,6 @@ proc stop(node: BeaconNode) = node.db.close() notice "Databases closed" -proc startBackfillTask(node: BeaconNode) {.async.} = - while node.dag.needsBackfill: - if not node.syncManager.inProgress: - # Only start the backfiller if it's needed _and_ head sync has completed - - # if we lose sync after having synced head, we could stop the backfilller, - # but this should be a fringe case - might as well keep the logic simple for - # now - node.backfiller.start() - return - - await sleepAsync(chronos.seconds(2)) - proc run(node: BeaconNode) {.raises: [CatchableError].} = bnStatus = BeaconNodeStatus.Running @@ -2026,9 +2095,7 @@ proc run(node: BeaconNode) {.raises: [CatchableError].} = node.startLightClient() node.requestManager.start() - node.syncManager.start() - - if node.dag.needsBackfill(): asyncSpawn node.startBackfillTask() + node.syncOverseer.start() waitFor node.updateGossipStatus(wallSlot) diff --git a/beacon_chain/rpc/rest_rewards_api.nim b/beacon_chain/rpc/rest_rewards_api.nim index 1e6aeb331..44f5f9eb3 100644 --- a/beacon_chain/rpc/rest_rewards_api.nim +++ b/beacon_chain/rpc/rest_rewards_api.nim @@ -82,7 +82,7 @@ proc installRewardsApiHandlers*(router: var RestRouter, node: BeaconNode) = tmpState = assignClone(node.dag.headState) if not updateState( - node.dag, tmpState[], targetBlock, false, cache): + node.dag, tmpState[], targetBlock, false, cache, node.dag.updateFlags): return RestApiResponse.jsonError(Http404, ParentBlockMissingStateError) func rollbackProc(state: var ForkedHashedBeaconState) {. @@ -164,7 +164,7 @@ proc installRewardsApiHandlers*(router: var RestRouter, node: BeaconNode) = tmpState = assignClone(node.dag.headState) if not updateState( - node.dag, tmpState[], targetBlock, false, cache): + node.dag, tmpState[], targetBlock, false, cache, node.dag.updateFlags): return RestApiResponse.jsonError(Http404, ParentBlockMissingStateError) let response = diff --git a/beacon_chain/rpc/rest_utils.nim b/beacon_chain/rpc/rest_utils.nim index 0095bd1b0..6885fc806 100644 --- a/beacon_chain/rpc/rest_utils.nim +++ b/beacon_chain/rpc/rest_utils.nim @@ -192,7 +192,8 @@ template withStateForBlockSlotId*(nodeParam: BeaconNode, else: assignClone(node.dag.headState) - if node.dag.updateState(stateToAdvance[], blockSlotId, false, cache): + if node.dag.updateState(stateToAdvance[], blockSlotId, false, cache, + node.dag.updateFlags): if cachedState == nil and node.stateTtlCache != nil: # This was not a cached state, we can cache it now node.stateTtlCache.add(stateToAdvance) diff --git a/beacon_chain/spec/signatures_batch.nim b/beacon_chain/spec/signatures_batch.nim index 83657ebba..be31fb29d 100644 --- a/beacon_chain/spec/signatures_batch.nim +++ b/beacon_chain/spec/signatures_batch.nim @@ -229,6 +229,38 @@ func bls_to_execution_change_signature_set*( SignatureSet.init(pubkey, signing_root, signature) +proc collectProposerSignatureSet*( + sigs: var seq[SignatureSet], + blocks: openArray[ForkedSignedBeaconBlock], + validatorKeys: openArray[ImmutableValidatorData2], + fork: Fork, + genesis_validators_root: Eth2Digest +): Result[void, string] = + mixin load + + for forkedBlock in blocks: + let item = + withBlck(forkedBlock): + let + proposerKey = + validatorKeys.load(forkyBlck.message.proposer_index).valueOr: + let msg = "collectProposerSignatureSet: " & + "invalid proposer index (" & + $forkyBlck.message.proposer_index & ")" + return err(msg) + signature = + forkyBlck.signature.load().valueOr: + let msg = "collectProposerSignatureSet: " & + "cannot load signature (" & + $ forkyBlck.signature & ")" + return err(msg) + block_signature_set( + fork, genesis_validators_root, + forkyBlck.message.slot, forkyBlck.root, + proposerKey, signature) + sigs.add(item) + ok() + proc collectSignatureSets*( sigs: var seq[SignatureSet], signed_block: ForkySignedBeaconBlock, diff --git a/beacon_chain/sync/sync_manager.nim b/beacon_chain/sync/sync_manager.nim index 6e7c17764..2e5decf00 100644 --- a/beacon_chain/sync/sync_manager.nim +++ b/beacon_chain/sync/sync_manager.nim @@ -72,7 +72,7 @@ type rangeAge: uint64 chunkSize: uint64 queue: SyncQueue[A] - syncFut: Future[void] + syncFut: Future[void].Raising([CancelledError]) blockVerifier: BlockVerifier inProgress*: bool insSyncSpeed*: float @@ -88,7 +88,14 @@ type BeaconBlocksRes = NetRes[List[ref ForkedSignedBeaconBlock, Limit MAX_REQUEST_BLOCKS]] - BlobSidecarsRes = NetRes[List[ref BlobSidecar, Limit(MAX_REQUEST_BLOB_SIDECARS)]] + BlobSidecarsRes = + NetRes[List[ref BlobSidecar, Limit(MAX_REQUEST_BLOB_SIDECARS)]] + + SyncBlockData* = object + blocks*: seq[ref ForkedSignedBeaconBlock] + blobs*: Opt[seq[BlobSidecars]] + + SyncBlockDataRes* = Result[SyncBlockData, string] proc now*(sm: typedesc[SyncMoment], slots: uint64): SyncMoment {.inline.} = SyncMoment(stamp: now(chronos.Moment), slots: slots) @@ -172,7 +179,7 @@ proc newSyncManager*[A, B](pool: PeerPool[A, B], res proc getBlocks[A, B](man: SyncManager[A, B], peer: A, - req: SyncRequest): Future[BeaconBlocksRes] {. + req: SyncRequest[A]): Future[BeaconBlocksRes] {. async: (raises: [CancelledError], raw: true).} = mixin getScore, `==` @@ -188,14 +195,19 @@ proc getBlocks[A, B](man: SyncManager[A, B], peer: A, beaconBlocksByRange_v2(peer, req.slot, req.count, 1'u64) -proc shouldGetBlobs[A, B](man: SyncManager[A, B], e: Epoch): bool = - let wallEpoch = man.getLocalWallSlot().epoch - e >= man.DENEB_FORK_EPOCH and +proc shouldGetBlobs[A, B](man: SyncManager[A, B], s: Slot): bool = + let + wallEpoch = man.getLocalWallSlot().epoch + epoch = s.epoch() + (epoch >= man.DENEB_FORK_EPOCH) and (wallEpoch < man.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS or - e >= wallEpoch - man.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) + epoch >= wallEpoch - man.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) + +proc shouldGetBlobs[A, B](man: SyncManager[A, B], r: SyncRequest[A]): bool = + man.shouldGetBlobs(r.slot) or man.shouldGetBlobs(r.slot + (r.count - 1)) proc getBlobSidecars[A, B](man: SyncManager[A, B], peer: A, - req: SyncRequest): Future[BlobSidecarsRes] + req: SyncRequest[A]): Future[BlobSidecarsRes] {.async: (raises: [CancelledError], raw: true).} = mixin getScore, `==` @@ -225,10 +237,10 @@ proc remainingSlots(man: SyncManager): uint64 = else: 0'u64 -func groupBlobs*[T](req: SyncRequest[T], - blocks: seq[ref ForkedSignedBeaconBlock], - blobs: seq[ref BlobSidecar]): - Result[seq[BlobSidecars], string] = +func groupBlobs*( + blocks: seq[ref ForkedSignedBeaconBlock], + blobs: seq[ref BlobSidecar] +): Result[seq[BlobSidecars], string] = var grouped = newSeq[BlobSidecars](len(blocks)) blob_cursor = 0 @@ -269,8 +281,93 @@ func checkBlobs(blobs: seq[BlobSidecars]): Result[void, string] = ? blob_sidecar[].verify_blob_sidecar_inclusion_proof() ok() -proc syncStep[A, B](man: SyncManager[A, B], index: int, peer: A) - {.async: (raises: [CancelledError]).} = +proc getSyncBlockData*[T]( + peer: T, + slot: Slot +): Future[SyncBlockDataRes] {.async: (raises: [CancelledError]).} = + mixin getScore + + logScope: + slot = slot + peer_score = peer.getScore() + peer_speed = peer.netKbps() + topics = "syncman" + + debug "Requesting block from peer" + + let blocksRange = + block: + let res = await beaconBlocksByRange_v2(peer, slot, 1'u64, 1'u64) + if res.isErr(): + peer.updateScore(PeerScoreNoValues) + return err("Failed to receive blocks on request [" & $res.error & "]") + res.get().asSeq + + if len(blocksRange) == 0: + peer.updateScore(PeerScoreNoValues) + return err("An empty range of blocks was returned by peer") + + if len(blocksRange) != 1: + peer.updateScore(PeerScoreBadResponse) + return err("Incorrect number of blocks was returned by peer, " & + $len(blocksRange)) + + debug "Received block on request" + + if blocksRange[0][].slot != slot: + peer.updateScore(PeerScoreBadResponse) + return err("The received block is not in the requested range") + + let (shouldGetBlob, blobsCount) = + withBlck(blocksRange[0][]): + when consensusFork >= ConsensusFork.Deneb: + let res = len(forkyBlck.message.body.blob_kzg_commitments) + if res > 0: + (true, res) + else: + (false, 0) + else: + (false, 0) + + let blobsRange = + if shouldGetBlob: + let blobData = + block: + debug "Requesting blobs sidecars from peer" + let res = await blobSidecarsByRange(peer, slot, 1'u64) + if res.isErr(): + peer.updateScore(PeerScoreNoValues) + return err( + "Failed to receive blobs on request, reason: " & $res.error) + res.get().asSeq() + + if len(blobData) == 0: + peer.updateScore(PeerScoreNoValues) + return err("An empty range of blobs was returned by peer") + + if len(blobData) != blobsCount: + peer.updateScore(PeerScoreBadResponse) + return err("Incorrect number of received blobs in the requested range") + + debug "Received blobs on request", blobs_count = len(blobData) + + let groupedBlobs = groupBlobs(blocksRange, blobData).valueOr: + peer.updateScore(PeerScoreNoValues) + return err("Received blobs sequence is inconsistent, reason: " & error) + + groupedBlobs.checkBlobs().isOkOr: + peer.updateScore(PeerScoreBadResponse) + return err("Received blobs sequence is invalid, reason: " & error) + + Opt.some(groupedBlobs) + else: + Opt.none(seq[BlobSidecars]) + + ok(SyncBlockData(blocks: blocksRange, blobs: blobsRange)) + +proc syncStep[A, B]( + man: SyncManager[A, B], index: int, peer: A +) {.async: (raises: [CancelledError]).} = logScope: peer_score = peer.getScore() peer_speed = peer.netKbps() @@ -409,21 +506,20 @@ proc syncStep[A, B](man: SyncManager[A, B], index: int, peer: A) request = req, err = blocks.error return let blockData = blocks.get().asSeq() - let blockSmap = getShortMap(req, blockData) debug "Received blocks on request", blocks_count = len(blockData), - blocks_map = blockSmap, request = req + blocks_map = getShortMap(req, blockData), request = req let slots = mapIt(blockData, it[].slot) if not(checkResponse(req, slots)): peer.updateScore(PeerScoreBadResponse) man.queue.push(req) warn "Received blocks sequence is not in requested range", - blocks_count = len(blockData), blocks_map = blockSmap, - request = req + blocks_count = len(blockData), + blocks_map = getShortMap(req, blockData), request = req return let shouldGetBlobs = - if not man.shouldGetBlobs(req.slot.epoch): + if not man.shouldGetBlobs(req): false else: var hasBlobs = false @@ -435,12 +531,6 @@ proc syncStep[A, B](man: SyncManager[A, B], index: int, peer: A) break hasBlobs - func combine(acc: seq[Slot], cur: Slot): seq[Slot] = - var copy = acc - if copy[copy.len-1] != cur: - copy.add(cur) - copy - let blobData = if shouldGetBlobs: let blobs = await man.getBlobSidecars(peer, req) @@ -451,37 +541,37 @@ proc syncStep[A, B](man: SyncManager[A, B], index: int, peer: A) request = req, err = blobs.error return let blobData = blobs.get().asSeq() - let blobSmap = getShortMap(req, blobData) - debug "Received blobs on request", blobs_count = len(blobData), - blobs_map = blobSmap, request = req + debug "Received blobs on request", + blobs_count = len(blobData), + blobs_map = getShortMap(req, blobData), request = req if len(blobData) > 0: let slots = mapIt(blobData, it[].signed_block_header.message.slot) - let uniqueSlots = foldl(slots, combine(a, b), @[slots[0]]) - if not(checkResponse(req, uniqueSlots)): + if not(checkResponse(req, slots)): peer.updateScore(PeerScoreBadResponse) man.queue.push(req) warn "Received blobs sequence is not in requested range", - blobs_count = len(blobData), blobs_map = getShortMap(req, blobData), - request = req + blobs_count = len(blobData), + blobs_map = getShortMap(req, blobData), + request = req return - let groupedBlobs = groupBlobs(req, blockData, blobData) - if groupedBlobs.isErr(): + let groupedBlobs = groupBlobs(blockData, blobData).valueOr: peer.updateScore(PeerScoreNoValues) man.queue.push(req) info "Received blobs sequence is inconsistent", - blobs_map = getShortMap(req, blobData), request = req, msg=groupedBlobs.error() + blobs_map = getShortMap(req, blobData), + request = req, msg = error return - if (let checkRes = groupedBlobs.get.checkBlobs(); checkRes.isErr): + if (let checkRes = groupedBlobs.checkBlobs(); checkRes.isErr): peer.updateScore(PeerScoreBadResponse) man.queue.push(req) warn "Received blobs sequence is invalid", - blobs_count = len(blobData), - blobs_map = getShortMap(req, blobData), - request = req, - msg = checkRes.error + blobs_count = len(blobData), + blobs_map = getShortMap(req, blobData), + request = req, + msg = checkRes.error return - Opt.some(groupedBlobs.get()) + Opt.some(groupedBlobs) else: Opt.none(seq[BlobSidecars]) @@ -512,7 +602,9 @@ proc syncStep[A, B](man: SyncManager[A, B], index: int, peer: A) await man.queue.push(req, blockData, blobData, maybeFinalized, proc() = man.workers[index].status = SyncWorkerStatus.Processing) -proc syncWorker[A, B](man: SyncManager[A, B], index: int) {.async: (raises: [CancelledError]).} = +proc syncWorker[A, B]( + man: SyncManager[A, B], index: int +) {.async: (raises: [CancelledError]).} = mixin getKey, getScore, getHeadSlot logScope: @@ -610,8 +702,9 @@ proc toTimeLeftString*(d: Duration): string = res = res & "00m" res -proc syncClose[A, B](man: SyncManager[A, B], - speedTaskFut: Future[void]) {.async.} = +proc syncClose[A, B]( + man: SyncManager[A, B], speedTaskFut: Future[void] +) {.async: (raises: []).} = var pending: seq[FutureBase] if not(speedTaskFut.finished()): pending.add(speedTaskFut.cancelAndWait()) @@ -620,7 +713,10 @@ proc syncClose[A, B](man: SyncManager[A, B], pending.add(worker.future.cancelAndWait()) await noCancel allFutures(pending) -proc syncLoop[A, B](man: SyncManager[A, B]) {.async.} = +proc syncLoop[A, B]( + man: SyncManager[A, B] +) {.async: (raises: [CancelledError]).} = + logScope: sync_ident = man.ident direction = man.direction @@ -671,14 +767,27 @@ proc syncLoop[A, B](man: SyncManager[A, B]) {.async.} = let (map, sleeping, waiting, pending) = man.getWorkersStats() - debug "Current syncing state", workers_map = map, - sleeping_workers_count = sleeping, - waiting_workers_count = waiting, - pending_workers_count = pending, - wall_head_slot = wallSlot, local_head_slot = headSlot, - pause_time = $chronos.seconds(pauseTime), - avg_sync_speed = man.avgSyncSpeed, ins_sync_speed = man.insSyncSpeed - + case man.queue.kind + of SyncQueueKind.Forward: + debug "Current syncing state", workers_map = map, + sleeping_workers_count = sleeping, + waiting_workers_count = waiting, + pending_workers_count = pending, + wall_head_slot = wallSlot, + local_head_slot = headSlot, + pause_time = $chronos.seconds(pauseTime), + avg_sync_speed = man.avgSyncSpeed.formatBiggestFloat(ffDecimal, 4), + ins_sync_speed = man.insSyncSpeed.formatBiggestFloat(ffDecimal, 4) + of SyncQueueKind.Backward: + debug "Current syncing state", workers_map = map, + sleeping_workers_count = sleeping, + waiting_workers_count = waiting, + pending_workers_count = pending, + wall_head_slot = wallSlot, + backfill_slot = man.getSafeSlot(), + pause_time = $chronos.seconds(pauseTime), + avg_sync_speed = man.avgSyncSpeed.formatBiggestFloat(ffDecimal, 4), + ins_sync_speed = man.insSyncSpeed.formatBiggestFloat(ffDecimal, 4) let pivot = man.progressPivot progress = @@ -806,3 +915,18 @@ proc syncLoop[A, B](man: SyncManager[A, B]) {.async.} = proc start*[A, B](man: SyncManager[A, B]) = ## Starts SyncManager's main loop. man.syncFut = man.syncLoop() + +proc updatePivot*[A, B](man: SyncManager[A, B], pivot: Slot) = + ## Update progress pivot slot. + man.progressPivot = pivot + +proc join*[A, B]( + man: SyncManager[A, B] +): Future[void] {.async: (raw: true, raises: [CancelledError]).} = + if man.syncFut.isNil(): + let retFuture = + Future[void].Raising([CancelledError]).init("nimbus-eth2.join()") + retFuture.complete() + retFuture + else: + man.syncFut.join() diff --git a/beacon_chain/sync/sync_overseer.nim b/beacon_chain/sync/sync_overseer.nim new file mode 100644 index 000000000..4dbf70cc8 --- /dev/null +++ b/beacon_chain/sync/sync_overseer.nim @@ -0,0 +1,501 @@ +# beacon_chain +# Copyright (c) 2018-2024 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import std/[strutils, sequtils] +import stew/base10, chronos, chronicles, results +import + ../consensus_object_pools/blockchain_list, + ../spec/eth2_apis/rest_types, + ../spec/[helpers, forks, network, forks_light_client, weak_subjectivity], + ../networking/[peer_pool, peer_scores, eth2_network], + ../gossip_processing/block_processor, + ../[beacon_clock, beacon_node], + ./[sync_types, sync_manager, sync_queue] + +from ../consensus_object_pools/spec_cache import get_attesting_indices + +export sync_types + +logScope: + topics = "overseer" + +const + PARALLEL_REQUESTS = 3 + ## Number of peers used to obtain the initial block. + BLOCKS_PROCESS_CHUNK_SIZE = 2 + ## Number of blocks sent to processing (CPU heavy task). + +type + BlockDataRes = Result[BlockData, string] + +proc init*(t: typedesc[BlockDataChunk], + stateCallback: OnStateUpdated, + data: openArray[BlockData]): BlockDataChunk = + BlockDataChunk( + blocks: @data, + onStateUpdatedCb: stateCallback, + resfut: + Future[Result[void, string]].Raising([CancelledError]).init( + "blockdata.chunk") + ) + +proc shortLog*(c: BlockDataChunk): string = + let + map = + (c.blocks.mapIt(shortLog(it.blck.root) & ":" & $it.blck.slot)). + join(", ") + futureState = if c.resfut.finished(): "pending" else: "completed" + "[" & map & "]:" & futureState + +iterator chunks*(data: openArray[BlockData], + stateCallback: OnStateUpdated, + maxCount: Positive): BlockDataChunk = + for i in countup(0, len(data) - 1, maxCount): + yield BlockDataChunk.init(stateCallback, + data.toOpenArray(i, min(i + maxCount, len(data)) - 1)) + +proc getLatestBeaconHeader( + overseer: SyncOverseerRef +): Future[BeaconBlockHeader] {.async: (raises: [CancelledError]).} = + let eventKey = overseer.eventQueue.register() + + defer: + overseer.eventQueue.unregister(eventKey) + + let events = + try: + await overseer.eventQueue.waitEvents(eventKey) + except CancelledError as exc: + raise exc + except AsyncEventQueueFullError: + raiseAssert "AsyncEventQueueFullError should not happen!" + + withForkyHeader(events[^1]): + when lcDataFork > LightClientDataFork.None: + forkyHeader.beacon + else: + raiseAssert "Should not happen" + +proc getPeerBlock( + overseer: SyncOverseerRef, + slot: Slot, +): Future[BlockDataRes] {.async: (raises: [CancelledError]).} = + let peer = await overseer.pool.acquire() + try: + let + res = (await getSyncBlockData(peer, slot)).valueOr: + return err(error) + blob = + if res.blobs.isSome(): + Opt.some(res.blobs.get()[0]) + else: + Opt.none(BlobSidecars) + ok(BlockData(blck: res.blocks[0][], blob: blob)) + finally: + overseer.pool.release(peer) + +proc getBlock( + overseer: SyncOverseerRef, + slot: Slot, + blockHeader: BeaconBlockHeader +): Future[BlockData] {.async: (raises: [CancelledError]).} = + var workers: + array[PARALLEL_REQUESTS, Future[BlockDataRes].Raising([CancelledError])] + + while true: + for i in 0 ..< PARALLEL_REQUESTS: + workers[i] = overseer.getPeerBlock(slot) + + try: + await allFutures(workers) + except CancelledError as exc: + let pending = + workers.filterIt(not(it.finished())).mapIt(cancelAndWait(it)) + await noCancel allFutures(pending) + raise exc + + var results: seq[BlockData] + for i in 0 ..< PARALLEL_REQUESTS: + if workers[i].value.isOk: + results.add(workers[i].value.get()) + + if len(results) > 0: + for item in results: + withBlck(item.blck): + if forkyBlck.message.toBeaconBlockHeader() == blockHeader: + return item + + # Wait for 2 seconds before trying one more time. + await sleepAsync(2.seconds) + +proc isWithinWeakSubjectivityPeriod( + overseer: SyncOverseerRef, slot: Slot): bool = + let + dag = overseer.consensusManager.dag + currentSlot = overseer.beaconClock.now().slotOrZero() + checkpoint = Checkpoint( + epoch: + getStateField(dag.headState, slot).epoch(), + root: + getStateField(dag.headState, latest_block_header).state_root) + + is_within_weak_subjectivity_period( + dag.cfg, currentSlot, dag.headState, checkpoint) + +proc isUntrustedBackfillEmpty(clist: ChainListRef): bool = + clist.tail.isNone() + +func speed(start, finish: Moment, entities: int): float = + if entities <= 0: + 0.0 + else: + float(entities) / toFloatSeconds(finish - start) + +proc updatePerformance(overseer: SyncOverseerRef, startTick: Moment, + entities: int) = + let dag = overseer.consensusManager.dag + doAssert(overseer.clist.head.isSome() and overseer.clist.tail.isSome()) + let + clistHeadSlot = overseer.clist.head.get().slot + clistTailSlot = overseer.clist.tail.get().slot + doAssert(clistHeadSlot >= dag.head.slot) + let slotsPerSec = speed(startTick, Moment.now(), entities) + + inc(overseer.avgSpeedCounter) + overseer.avgSpeed = overseer.avgSpeed + + (slotsPerSec - overseer.avgSpeed) / float(overseer.avgSpeedCounter) + + let + total = clistHeadSlot - clistTailSlot + progress = dag.head.slot - clistTailSlot + done = float(progress) / float(total) + remaining = total - progress + timeleft = + if overseer.avgSpeed >= 0.001: + Duration.fromFloatSeconds(remaining.float / overseer.avgSpeed) + else: + InfiniteDuration + + # Update status string + overseer.statusMsg = Opt.some( + timeleft.toTimeLeftString() & " (" & + (done * 100).formatBiggestFloat(ffDecimal, 2) & "%) " & + overseer.avgSpeed.formatBiggestFloat(ffDecimal, 4) & + "slots/s (" & $dag.head.slot & ")") + +proc blockProcessingLoop(overseer: SyncOverseerRef): Future[void] {. + async: (raises: [CancelledError]).} = + let + consensusManager = overseer.consensusManager + dag = consensusManager.dag + attestationPool = consensusManager.attestationPool + validatorMonitor = overseer.validatorMonitor + + proc onBlockAdded( + blckRef: BlockRef, blck: ForkedTrustedSignedBeaconBlock, epochRef: EpochRef, + unrealized: FinalityCheckpoints) {.gcsafe, raises: [].} = + + let wallTime = overseer.getBeaconTimeFn() + withBlck(blck): + attestationPool[].addForkChoice( + epochRef, blckRef, unrealized, forkyBlck.message, wallTime) + + validatorMonitor[].registerBeaconBlock( + MsgSource.sync, wallTime, forkyBlck.message) + + for attestation in forkyBlck.message.body.attestations: + for validator_index in + dag.get_attesting_indices(attestation, true): + validatorMonitor[].registerAttestationInBlock( + attestation.data, validator_index, forkyBlck.message.slot) + + withState(dag[].clearanceState): + when (consensusFork >= ConsensusFork.Altair) and + (type(forkyBlck) isnot phase0.TrustedSignedBeaconBlock): + for i in forkyBlck.message.body.sync_aggregate. + sync_committee_bits.oneIndices(): + validatorMonitor[].registerSyncAggregateInBlock( + forkyBlck.message.slot, forkyBlck.root, + forkyState.data.current_sync_committee.pubkeys.data[i]) + + block mainLoop: + while true: + let bchunk = await overseer.blocksQueue.popFirst() + + block innerLoop: + for bdata in bchunk.blocks: + block: + let res = addBackfillBlockData(dag, bdata, bchunk.onStateUpdatedCb, + onBlockAdded) + if res.isErr(): + let msg = "Unable to add block data to database [" & + $res.error & "]" + bchunk.resfut.complete(Result[void, string].err(msg)) + break innerLoop + + consensusManager.updateHead(overseer.getBeaconTimeFn).isOkOr: + bchunk.resfut.complete(Result[void, string].err(error)) + break innerLoop + + bchunk.resfut.complete(Result[void, string].ok()) + +proc verifyBlockProposer( + fork: Fork, + genesis_validators_root: Eth2Digest, + immutableValidators: openArray[ImmutableValidatorData2], + signedBlock: ForkedSignedBeaconBlock +): Result[void, cstring] = + withBlck(signedBlock): + let proposerKey = + immutableValidators.load(forkyBlck.message.proposer_index).valueOr: + return err("Unable to find proposer key") + + if not(verify_block_signature(fork, genesis_validators_root, + forkyBlck.message.slot, forkyBlck.message, + proposerKey, forkyBlck.signature)): + return err("Signature verification failed") + + ok() + +proc rebuildState(overseer: SyncOverseerRef): Future[void] {. + async: (raises: [CancelledError]).} = + overseer.statusMsg = Opt.some("rebuilding state") + let + consensusManager = overseer.consensusManager + dag = consensusManager.dag + batchVerifier = overseer.batchVerifier + clist = + block: + overseer.clist.seekForSlot(dag.head.slot).isOkOr: + fatal "Unable to find slot in backfill data", reason = error, + path = overseer.clist.path + quit 1 + overseer.clist + + var + blocks: seq[BlockData] + currentEpoch: Epoch = FAR_FUTURE_EPOCH + + let handle = clist.handle.get() + + overseer.avgSpeed = 0.0 + overseer.avgSpeedCounter = 0 + + # Set minimum slot number from which LC data is collected. + dag.lcDataStore.cache.tailSlot = clist.head.get().slot + + block mainLoop: + while true: + let res = getChainFileTail(handle.handle) + if res.isErr(): + fatal "Unable to read backfill data", reason = res.error + quit 1 + let bres = res.get() + if bres.isNone(): + return + + let + data = bres.get() + blockEpoch = data.blck.slot.epoch() + + if blockEpoch != currentEpoch: + if len(blocks) != 0: + let + startTick = Moment.now() + blocksOnly = blocks.mapIt(it.blck) + + proc onStateUpdate(slot: Slot): Result[void, VerifierError] {. + gcsafe, raises: [].} = + + if slot != blocksOnly[0].slot: + # We verify signatures only at the beginning of chunk/epoch, in + # such way we could verify whole epoch's proposer signatures in + # one batch. + return ok() + + let + fork = + getStateField(dag.headState, fork) + genesis_validators_root = + getStateField(dag.headState, genesis_validators_root) + + verifyBlockProposer(batchVerifier[], fork, genesis_validators_root, + dag.db.immutableValidators, blocksOnly).isOkOr: + for signedBlock in blocksOnly: + verifyBlockProposer(fork, genesis_validators_root, + dag.db.immutableValidators, + signedBlock).isOkOr: + fatal "Unable to verify block proposer", + blck = shortLog(signedBlock), reason = error + return err(VerifierError.Invalid) + ok() + + for bchunk in blocks.chunks(onStateUpdate, BLOCKS_PROCESS_CHUNK_SIZE): + try: + overseer.blocksQueue.addLastNoWait(bchunk) + except AsyncQueueFullError: + raiseAssert "Should not happen with unbounded AsyncQueue" + let res = await bchunk.resfut + if res.isErr(): + fatal "Unable to add block data to database", reason = res.error + quit 1 + + let updateTick = Moment.now() + debug "Number of blocks injected", + blocks_count = len(blocks), + head = shortLog(dag.head), + finalized = shortLog(getStateField( + dag.headState, finalized_checkpoint)), + store_update_time = updateTick - startTick + + overseer.updatePerformance(startTick, len(blocks)) + blocks.setLen(0) + + currentEpoch = blockEpoch + + if data.blck.slot != GENESIS_SLOT: + blocks.add(data) + +proc initUntrustedSync(overseer: SyncOverseerRef): Future[void] {. + async: (raises: [CancelledError]).} = + + overseer.statusMsg = Opt.some("awaiting light client") + + let blockHeader = await overseer.getLatestBeaconHeader() + + notice "Received light client block header", + beacon_header = shortLog(blockHeader), + current_slot = overseer.beaconClock.now().slotOrZero() + + overseer.statusMsg = Opt.some("retrieving block") + + let + blck = await overseer.getBlock(blockHeader.slot, blockHeader) + blobsCount = if blck.blob.isNone(): 0 else: len(blck.blob.get()) + + notice "Received beacon block", blck = shortLog(blck.blck), + blobs_count = blobsCount + + overseer.statusMsg = Opt.some("storing block") + + let res = overseer.clist.addBackfillBlockData(blck.blck, blck.blob) + if res.isErr(): + warn "Unable to store initial block", reason = res.error + return + + overseer.statusMsg = Opt.none(string) + + notice "Initial block being stored", + blck = shortLog(blck.blck), blobs_count = blobsCount + +proc startBackfillTask(overseer: SyncOverseerRef): Future[void] {. + async: (raises: []).} = + # This procedure performs delayed start of backfilling process. + while overseer.consensusManager.dag.needsBackfill: + if not(overseer.forwardSync.inProgress): + # Only start the backfiller if it's needed _and_ head sync has completed - + # if we lose sync after having synced head, we could stop the backfilller, + # but this should be a fringe case - might as well keep the logic simple + # for now. + overseer.backwardSync.start() + return + try: + await sleepAsync(chronos.seconds(2)) + except CancelledError: + return + +proc mainLoop*( + overseer: SyncOverseerRef +): Future[void] {.async: (raises: []).} = + let + dag = overseer.consensusManager.dag + clist = overseer.clist + currentSlot = overseer.beaconClock.now().slotOrZero() + + if overseer.isWithinWeakSubjectivityPeriod(currentSlot): + # Starting forward sync manager/monitor. + overseer.forwardSync.start() + # Starting backfill/backward sync manager. + if dag.needsBackfill(): + asyncSpawn overseer.startBackfillTask() + return + else: + if dag.needsBackfill(): + # Checkpoint/Trusted state we have is too old. + error "Trusted node sync started too long time ago" + quit 1 + + if not(isUntrustedBackfillEmpty(clist)): + let headSlot = clist.head.get().slot + if not(overseer.isWithinWeakSubjectivityPeriod(headSlot)): + # Light forward sync file is too old. + warn "Light client sync was started too long time ago", + current_slot = currentSlot, backfill_data_slot = headSlot + + if overseer.config.longRangeSync == LongRangeSyncMode.Lenient: + # Starting forward sync manager/monitor only. + overseer.forwardSync.start() + return + + if overseer.config.longRangeSync == LongRangeSyncMode.Light: + let dagHead = dag.finalizedHead + if dagHead.slot < dag.cfg.ALTAIR_FORK_EPOCH.start_slot: + fatal "Light forward syncing requires a post-Altair state", + head_slot = dagHead.slot, + altair_start_slot = dag.cfg.ALTAIR_FORK_EPOCH.start_slot + quit 1 + + if isUntrustedBackfillEmpty(clist): + overseer.untrustedInProgress = true + + try: + await overseer.initUntrustedSync() + except CancelledError: + return + # We need to update pivot slot to enable timeleft calculation. + overseer.untrustedSync.updatePivot(overseer.clist.tail.get().slot) + # Note: We should not start forward sync manager! + overseer.untrustedSync.start() + + # Waiting until untrusted backfilling will not be complete + try: + await overseer.untrustedSync.join() + except CancelledError: + return + + notice "Start state rebuilding process" + # We spawn block processing loop to keep async world happy, otherwise + # it could be single cpu heavy procedure call. + let blockProcessingFut = overseer.blockProcessingLoop() + + try: + await overseer.rebuildState() + except CancelledError: + await cancelAndWait(blockProcessingFut) + return + + clist.clear().isOkOr: + warn "Unable to remove backfill data file", + path = clist.path.chainFilePath(), reason = error + quit 1 + + overseer.untrustedInProgress = false + + # When we finished state rebuilding process - we could start forward + # SyncManager which could perform finish sync. + overseer.forwardSync.start() + +proc start*(overseer: SyncOverseerRef) = + overseer.loopFuture = overseer.mainLoop() + +proc stop*(overseer: SyncOverseerRef) {.async: (raises: []).} = + doAssert(not(isNil(overseer.loopFuture)), + "SyncOverseer was not started yet") + if not(overseer.loopFuture.finished()): + await cancelAndWait(overseer.loopFuture) diff --git a/beacon_chain/sync/sync_types.nim b/beacon_chain/sync/sync_types.nim new file mode 100644 index 000000000..1de01d5b1 --- /dev/null +++ b/beacon_chain/sync/sync_types.nim @@ -0,0 +1,85 @@ +# beacon_chain +# Copyright (c) 2018-2024 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import results, chronos, + ".."/spec/[forks_light_client, signatures_batch], + ".."/consensus_object_pools/[block_pools_types, blockchain_dag, + attestation_pool, blockchain_list, + consensus_manager], + ".."/validators/validator_monitor, + ".."/[beacon_clock, conf], + ".."/networking/eth2_network, + "."/sync_manager + +export results, chronos, block_pools_types, conf + +type + BlockDataChunk* = ref object + resfut*: Future[Result[void, string]].Raising([CancelledError]) + onStateUpdatedCb*: OnStateUpdated + blocks*: seq[BlockData] + + SyncOverseer* = object + statusMsg*: Opt[string] + consensusManager*: ref ConsensusManager + validatorMonitor*: ref ValidatorMonitor + config*: BeaconNodeConf + getBeaconTimeFn*: GetBeaconTimeFn + clist*: ChainListRef + beaconClock*: BeaconClock + eventQueue*: AsyncEventQueue[ForkedLightClientHeader] + loopFuture*: Future[void].Raising([]) + forwardSync*: SyncManager[Peer, PeerId] + backwardSync*: SyncManager[Peer, PeerId] + untrustedSync*: SyncManager[Peer, PeerId] + batchVerifier*: ref BatchVerifier + pool*: PeerPool[Peer, PeerId] + avgSpeedCounter*: int + avgSpeed*: float + blocksQueue*: AsyncQueue[BlockDataChunk] + untrustedInProgress*: bool + + SyncOverseerRef* = ref SyncOverseer + +proc new*( + t: typedesc[SyncOverseerRef], + cm: ref ConsensusManager, + vm: ref ValidatorMonitor, + configuration: BeaconNodeConf, + bt: GetBeaconTimeFn, + clist: ChainListRef, + clock: BeaconClock, + eq: AsyncEventQueue[ForkedLightClientHeader], + pool: PeerPool[Peer, PeerId], + batchVerifier: ref BatchVerifier, + forwardSync: SyncManager[Peer, PeerId], + backwardSync: SyncManager[Peer, PeerId], + untrustedSync: SyncManager[Peer, PeerId] +): SyncOverseerRef = + SyncOverseerRef( + consensusManager: cm, + validatorMonitor: vm, + config: configuration, + getBeaconTimeFn: bt, + clist: clist, + beaconClock: clock, + eventQueue: eq, + pool: pool, + batchVerifier: batchVerifier, + forwardSync: forwardSync, + backwardSync: backwardSync, + untrustedSync: untrustedSync, + untrustedInProgress: false, + blocksQueue: newAsyncQueue[BlockDataChunk]()) + +proc syncInProgress*(overseer: SyncOverseerRef): bool = + overseer.forwardSync.inProgress or + overseer.backwardSync.inProgress or + overseer.untrustedSync.inProgress or + overseer.untrustedInProgress diff --git a/beacon_chain/validators/validator_monitor.nim b/beacon_chain/validators/validator_monitor.nim index bee1c7238..1259cfeec 100644 --- a/beacon_chain/validators/validator_monitor.nim +++ b/beacon_chain/validators/validator_monitor.nim @@ -211,6 +211,7 @@ type # expanded in the future. gossip = "gossip" api = "api" + sync = "sync" template toGaugeValue(v: bool): int64 = if v: 1 else: 0 diff --git a/ncli/ncli_db.nim b/ncli/ncli_db.nim index 4f46f9503..14c0340c3 100644 --- a/ncli/ncli_db.nim +++ b/ncli/ncli_db.nim @@ -295,7 +295,7 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) = doAssert dag.updateState( stateData[], dag.atSlot(blockRefs[^1], blockRefs[^1].slot - 1).expect("not nil"), - false, cache) + false, cache, dag.updateFlags) template processBlocks(blocks: auto) = for b in blocks.mitems(): @@ -612,7 +612,8 @@ proc cmdExportEra(conf: DbConf, cfg: RuntimeConfig) = withTimer(timers[tState]): var cache: StateCache - if not updateState(dag, tmpState[], eraBid, false, cache): + if not updateState(dag, tmpState[], eraBid, false, cache, + dag.updateFlags): notice "Skipping era, state history not available", era, name missingHistory = true continue @@ -753,7 +754,7 @@ proc cmdValidatorPerf(conf: DbConf, cfg: RuntimeConfig) = doAssert dag.updateState( state[], dag.atSlot(blockRefs[^1], blockRefs[^1].slot - 1).expect("block found"), - false, cache) + false, cache, dag.updateFlags) proc processEpoch() = let @@ -1051,10 +1052,12 @@ proc cmdValidatorDb(conf: DbConf, cfg: RuntimeConfig) = let slot = if startEpochSlot > 0: startEpochSlot - 1 else: 0.Slot if blockRefs.len > 0: discard dag.updateState( - tmpState[], dag.atSlot(blockRefs[^1], slot).expect("block"), false, cache) + tmpState[], dag.atSlot(blockRefs[^1], slot).expect("block"), false, cache, + dag.updateFlags) else: discard dag.updateState( - tmpState[], dag.getBlockIdAtSlot(slot).expect("block"), false, cache) + tmpState[], dag.getBlockIdAtSlot(slot).expect("block"), false, cache, + dag.updateFlags) let savedValidatorsCount = outDb.getDbValidatorsCount var validatorsCount = getStateField(tmpState[], validators).len @@ -1213,4 +1216,4 @@ when isMainModule: of DbCmd.validatorPerf: cmdValidatorPerf(conf, cfg) of DbCmd.validatorDb: - cmdValidatorDb(conf, cfg) \ No newline at end of file + cmdValidatorDb(conf, cfg) diff --git a/research/block_sim.nim b/research/block_sim.nim index 9fcc7b636..6662a9849 100644 --- a/research/block_sim.nim +++ b/research/block_sim.nim @@ -532,8 +532,8 @@ cli do(slots = SLOTS_PER_EPOCH * 7, var cache = StateCache() doAssert dag.updateState( replayState[], dag.getBlockIdAtSlot(Slot(slots)).expect("block"), - false, cache) + false, cache, dag.updateFlags) echo "Done!" - printTimers(dag.headState, attesters, true, timers) \ No newline at end of file + printTimers(dag.headState, attesters, true, timers) diff --git a/tests/all_tests.nim b/tests/all_tests.nim index 614428be9..c9df26277 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -61,9 +61,10 @@ import # Unit test ./slashing_protection/test_fixtures, ./slashing_protection/test_slashing_protection_db, ./test_validator_client, - ./test_beacon_validators + ./test_beacon_validators, + ./test_beacon_chain_file when not defined(windows): import ./test_keymanager_api -summarizeLongTests("AllTests") \ No newline at end of file +summarizeLongTests("AllTests") diff --git a/tests/consensus_spec/test_fixture_fork_choice.nim b/tests/consensus_spec/test_fixture_fork_choice.nim index d5df8a37d..b735640c3 100644 --- a/tests/consensus_spec/test_fixture_fork_choice.nim +++ b/tests/consensus_spec/test_fixture_fork_choice.nim @@ -196,7 +196,8 @@ proc stepOnBlock( state, dag.getBlockIdAtSlot(time.slotOrZero).expect("block exists"), save = false, - stateCache + stateCache, + dag.updateFlags ) # 3. Add block to DAG diff --git a/tests/fixtures/bfdata-test.bin b/tests/fixtures/bfdata-test.bin new file mode 100644 index 0000000000000000000000000000000000000000..6a039fcaf4db1b2667b57f16e95cb96129c5582f GIT binary patch literal 292527 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ਫ਼zVHgYQ5T}X1$T(sS$mn*GKLeu#GP=`X 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

!}nPyX8XF6h7|yuc#sb457}J!4?#4W zU+jt54w7vsh>ApJsj5Qp2Dps27H0DB`O;YIQKGyd<{S#;W@-IH^0RD#MScZ#-?2~t zQqS-%3x?tz4=8cEEpI=pqGYotGJ4YiunAh!@{ubyTyP z2b`@K{>-Yd|6r)tSJe)eXw2j(o+=_Q&H#J0@xNARIb#-!;98$N>4|x@hgk$`XaIaj zNCel?OZz7x1d7?Z@-QL_mkasv!eIfwV!K!qjc^X+X?mzMiu|&Xi#9hQs9zn+saxMe z`2zquKh+O&37K48PJJF!-(sVYS}%uQ;+*cr3OidmyNt2Ln-v4pibv~P*{>|gw*?_a z>z{9xe*Tps6tD~taK;b{;>aiK!?6;zy8vL>ejeaFE~G05;FnNQdELm-Cjx!cOfTM1!73P)~4OjmX z{!&O(+Z}bZTD(gnKk%HJS(ic9C3PZ{ByK!CRx~jN1;^on1;2-cdy#K(XuENII6eV$ zs=mf(F>E`ui!iQz7g*C?2}7#*qpMsYuT*y^pT_;Dr|9|cjA6$gvkcfSj+|77+57q5 zzw9*A%l>N;1)TRG-X(nEjo3WU}v{2NnB0G$U`Gi zzr@ai5Fi7K{UteSL*;59tGr4PF6n&B1m_)*UH4P)^r^fk;{T++53* z(Zhe*(wSj?wge4kqP#SK*vgcyuy+%8fu&79`r9|M&rt%B{%Dr*DWyu1Z%_NIkbvkA z2Z_3(A=pBJkH+d5>qIyV7%gIfVYh-2?6zr2n6w$@v+Hy*lz(8%#n3dhw-P&QQMTW} z38H&_nrPwWfcKa*$hkA2+S_5UYqzLgs4!#g(mOetJ^llQh%bX4wSu7Hejv|#*A!p~ z!AS~L_6rjWrQ^7@>NG{;qgSo!zmu|5OMhUQsl^4YKV8NPY7a%HCW!Qx-7j%xX-z#v zhe=SxzLdQ_{bf{Nak-i+F}2n9r=Cn7UjD{@220i{!P9<>%Ŗh1ZC6GD{CQepM4 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

1%hMhqbUEe$2b6Mwq8A}yHCsND-jtbn%>RWJp= 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ȗsjG=`_5y@cFHon$X|(P~}^8vPEplSBVP| z!P<=O+6}k39@kE=>z)Hicg}b|uKnnyGQGaagZDi@`^}7u{4y;p7*N=sx@!snB!J zrLc$kPmb1C*>Jy%FN|be$ZgGC18-q3uPTOqCHi)$cOR+v*_c*%XdY2(hWLDW_qT|* zq%FuPK)-!llIb8q-U`F&pAnSu-5Xg*uMTK|sxDE|6#g}m?y4GD2u~QUyNOtB$!TxKG^oF+nWd}$6(4OfNvqQK0 z=~5eaR`{C#xIRW7Me3%MK5lqheHY(w^9==Su}AM!q;@tlU<_b4%)+;-^vhQMeCDe);ZH6u5aoq`*s`7URo)S}Ocj>q8K)>aRIMzS z#d=+ISZU$w2ubX*g;WV^-%$nspVX{0Ly zFUNu;9X>K`v*;O|Pv9_U3Mw-F^X(;%{9wItlwWPZ{ab~IWU&#{T~~@h=2I06Pkvp@ zK+TkT%d9_Hrnj%U__0IVIEE~C>n$&ec61Qf{uH~oe=XBGGa=|Dzv#8FP|Hg9fDXSA zpL$9^L{+~fzVs5cCaZ^2tW7&YbB^QC{^{9oayr@_8pL|lFDM9om}%9y;qiA5h0O`r ziYuER&9-yzBd$x2K2qd=uyrkk{#0~q9e?vai^q>61wt@wM)u6r-;@tE1w~?b_{B7) z-kmPGE%qk^d2_(^^g_#Ai`p=|NsJ9XIn>x%%3N4mmQs@Nwf5y-N2)BJ6^5o6Tz+&j8rY>D?Hjo_j}^#5|APeII|mrU&GwB{zlVazLFF_)tp(nC9~;G zbNn>_-S44;KCkFfU;6thsi(JJJg52Tt?(K7&0)tzNA{Tq**xtd9+be&C0Thnmd*6{ zMb>fB-iqHBG>NAD00gzx$EsPMYo z@VS35I!gEuYN$FA&PrmQ%9(HY^Q4ai!iGn|OY(<(ASy_hS*$ zDeqH#&g5qt!21_LcFC8iSz-d|dmh$qPsBAL!n%L#zVG`}aGuCsFuHaytJzH}!u-G| zh_grJ&5i19RbxRzeP-9BucU9ikUg@6?6-qS8!i4?3*Y(nIPO}=7z=%vt?Nk5>#4@T z1&R<_qV=lAtWbB#yzg6Qv~r0UnsQWplJ4ekd6NZ*3>f);|8(ez((iSj(o&WfUOx`Y zv-otrNGr;0a><0d$Ks3k$b520-&V6;X|$#&I~8JdJA&#h^##QXg@0R{WL{ziPREEb z=rL7MzF=ZbE71ETwpRU47I}mIjd7~)clWZRqWr#HyKArPsnTc=2dYV@--;j6@Web2 zYVT33;+$3<>m(X|j;)M;h%Ys3BVRQ&b1RcU5as5Xa@ zw!po%r#_b~xRZFk?>=#kH|av%woDcXtmW}|{V3W*B3bCir>foI{ieA6JML)KiT;*{ zN+Z3sxecq>ZOgOXd~#)F6!#|dMEDI=827&hcfQVE@o}!Wk|B{yPqluLZi_eir~BLH z(yCkfSG??Gx;fD2`US7;GMKi`a%wmIR7jVY+`KEv&)`!2tWU%wad=jKUPoTVu%L>R z|5?DqAs3}S{q~FirCrt^qs|usOJQrumqXumT?z114(KZMdP<$S<|4V&6OEg4Dnkk!O@3w#zE1+auGhB24P){#@{eR8?%=M_H{Jp zFbY0QN(>au>tT`VWqh_HZy(~D-_Hi47hE}>r6`IJZoD0%@ng( zIWxU+R?ek|ywaNQ&!!u*YgyAKk`_0sTH^=@fk##EeO{_!b5HxDZd^ES)~sabjhVds zn?LcZx#*WPb)Edt#CwhQ!G6(ipK=YnLQuqte|Xg7^}zdJfYIUF;{e0DQ!y}HL1X58c$ts9uKSiUYT3cn$kevpar;vl+@ zLQNf@-?mr>p8mn^!@HmOo%(8oi+ACtgZ5vgf?Ql@?w-XfIWK8isP_tp`ss?*Ni76z zdwq^fx@F2u)>6N`_V8jLWr`|ws3YO`l#LS-D^TG(UHiBD%K^hgy8UB{;6TFd$8KB^ z=W4%3J!3m+d%Ss>o}uJ7c;(zedAVaGzE@>sok31telvzQY?FL1^~Fql`1zL9{lnXD zB2AAYIXIUD=}5n195kBU4mz}o(PwLPQ~3IUgk`{8i{9k@>N|Abm`sjfcR#!@BYaUOnTL|$l1Kqj^tt(P7UvD8eL)&q zEw!kE3gY(x&6gPVuiZvJ3}-37zGhe_p^R{9#h+!P1(~gqll*9&j`Q|?<>$WsG|E_g zgK^PPHYQrx8Y|P>mCY4C{&h6ZCZ%}_^#4tE&vPsiy*;Gv_>HMsw>UCr$|E2%7Zxp8t2V7X zj>1jkf3fFhY3475Qyt2x4+R0#t2*%nJ3&L6q-lp*w@6G=uZj4&ii+ge7l)t031igD zw`a5?`X_&dTg`dR4Xi3wUgF@7_F|m`kD68+W8NWN5;PsDpBAMzP%T-?+sj#pM{(eK zk}ho?Sv;3AwglxFFN5BSF}#=57I79IxBHsN>-xa!T2gA>-$u2c=p0`FkZ|5E@j;1@5{))8nh-YMu<<1s&VOZuwsnM`#(CZ377 zF3$p%+6neCch5oM@pdA$8n2b#2(#I64~eKavVNNKZliO?(+COx(F56v5vc9FI$2gmqWn+5U^^GFiW!v#0^6O}Je#c1N zmcc=B!N;0~r#U?ZL*_MJM-$ty$bFPA@>tO@Zt6N)PC0`cDZH5pXnws%5b#z9%nDD= zewf`QzN7z#K9y5V5%;Bt`+-nF9OC#m!oAanEA(^&d5w4~_bNlg$zh35d7E zcPi(eq;t{z2|q>q!XZR`$Tz4>XltOEY4Ti8TH;DEvENWsdy*E;;_%*koK~P`j9W6YqT?Y&Et^z1&$K=Lu; zLTdzxgplO$S?k%xD-+w?IeRM6zU}2yV0Oa2fLOdUN41QFMm>E{(j2`{+HjQnZ`Gv6FNMJ z;{i9^{9ErPu@0uJc{(GEOwPxb$)Z!rJ$lxEu{R`LWrH6^ugzx55O|(S-N!_snfbyf zd8d|gkL^{VU$GoN8^4!{>S`#;Gog^iNb9svtmv7@K)+cR*~rANUshwu?oAVnm%9etYF1|MeC1k9Cz>%LBh5gV}TsAdkcL9`d1tc1N>&&-kss+ z8ADX;==D{Y?}oS*R!O`Geevys3Leo#%fm9QQS?>2@R{Yd?+&Z;8#S{p&vZGw4+mbj zrj|9GS#U30d6@I?XQK3t-;d1_ex`KFx@6RU{k$|*_eowj>ct;UiLsX+MNV7>p6w|z z!tc%FZS4ON%b%6#aG9P%lD#+QaHHpsxl**muK#lV`)M+|Uh|j>{ny(*>2hoyE0+#3 zF6Iw~1abv0!8KiRW;c6%oPES_%wq+xXYvZ}2287{7{@ z{~JIdzbhB|RhCzew&+m53omtDC&7U6Q3c+=V2C|Uja{jem(pjaxMcB@q3v^r`$U!u zvsY|PGY4m7E0RUOCu7`| z`4n@(Y)wNl5xlpsab?(__ahZA-u@7j#l*_B7ee3!M2jsiS&*44)u zr*3cvR%sH|Xc?ChQ9R5;pXD{TTCpb1{c)b8-^XrL&apYjE~X^Y{*otS`GR+m_c#B5NNRZh5>erfkS-ag$rn#xJp*0)ne7QyU5* zu{Ta%yKs#c_0m_fXQ%qhR2fa&b$$thk#KrRSq`DwXwVwv7io*IaBcRFo-s`R>Q6%@U#^mw_QTBl_S|Tuu1wW;;?-3tF1z@Vi&uZS{h?EgQZmsbFjH~_q0WbsCtMGUj=(j%JV+nPs7A4 zIExCs8KNN}1g_H`s~vcTNqVtn(1@|1j<|eYeZ{`|Q$Cu5f#+NgXPdHU^}FPjj$GE+ zoLv7h*)?nJjK;n&<@9we6T8=Qi$@QZnUeX)23>}<>y`R0^G7KMgW|IweBf{Z3 zuD=%X!WkqtUYQ$6HdZqFMX9Sk|DcN9CwEmol;Nz_w(w2LRLLLToFDu6oKdPjD=5~} zPx@eD=X8rw>GW8`T$OS#qMqz=)2TGY{@Z7{tmVGs#$3Of5^5IM_#}H=lg)P7F}O$Z zX>tnbm-rF$${X@Wg*0QsuN)B%6qw4SOLGGAD98+cvG?&`)9Y!9%{-eWVYkI#z&shp zZJcVft!_7cbD@E#zbYcP#3k5h#q2ukPo*3&!(yhJUZH+h*(;u0MqfpUzW-}cpv@j~ zGqlb7l#?|2(Z|B_q7Txi{pC8?4)vIa)ItY`_@dq{6W=f=t2k>hII|LccPh+?w-H54 zPvascA+TszSiV7K=^}0IK9UyoIj&CPX*6YHPrKE~=l-bDO0I+bT>~QV>*Eel)9(~N zmn<|$#VE!+wcW4N^$&ZW^;<14x!BZAxbe?#;Y`mswu1v+M%TxL9!5Pa@xRo!n~EdFf!~i_Vb+Q_Gi);JZE}}vazfl#!7Ojgtk&ueKP z=j~TpN1*!?&VCf5eYa?;cy-J|(Kc(2+spks3FQk`kx(WUftj5grdp+cApY+M6)ME8 z50MFb$6!d84x8v{RL9XB%A}uMzK++(;ib(dx& zm#u$X`}Nju#^uJX6vv>>yOj7XWcv+D#}&tEofb>96+f2~^0(*N0g zq-4Kmv7^)K3UmAu-QeK>A^&X~lv)Lc;#o$uJpAt~Wh~nH6=V%Vzdnw3n3R~1j26Zl z**=u`tV2U9GnR_p972?aT4z^rXtx^1FkF_Aa%C4k{dh54JdBjDFma7`vN%R@e;~n2 znfP_3UFaX-Q=NU6JsN!%HW{uUB}C#p!tl=RMvgkl7GB*Jy4xNamTF!0_5HrLrBkCn zW}5pa*h&fuk$u)AO3e5^fMT@!i@8>OkT|PWwMA)WF$)0I=%QV?^b>{FCtWO^~uNrqC16UEEtIZa=j6@gGzZnzEq;yvs46vXC8rw`PbQVyGVB5lX<{b>uV>< z*GCKVRsWk80pbDSSToaL%J}+bU3b?8B5cIp6>O#*2e=|HzUa zRueWiikwKb3{r|>YRMwjX3q1ud_8}q-8He~`5w0}6@8_x_PW)|w2xFa;lRej1 z6PoI{=lAKG&(zUd!Jm?36y@=8;z9w3WxehYO$}c5nB+A%&Zc3R(Cat2^|`D6qQf{w zZ1hf8U_ncIA)#wPTXJKQKpXVfSop(%Z{Ps5%}-)idP?-m*&9VVwBr7R^Q>2_Vg)$O`u$Sv1f zo&ncGLl8;OME~92!sqawj|3+-BtXF@GXUQLz|!U@0Oc401^_(18DB|Qg2(U#l=Bk6 z_o2WZdJo_hKwV44G$s#!uT_jYgW^dC*Ai2Lm8=TUd9kd(kHJXOcU;1#xtF9o`9~Zn zg`}?)+5}0nSLgLY*;LeXj0vNH61983A}!8xzO}sz+y=i~W*Dar*&hpzWBIn5t6y*& z$NTG>oU+N1`iYFgfBxr=AVwfAL&tvx-E1DJM1~xJxC66j7bOD0OpQRe&>#@+Xc345 zXnI|G1R|XQftX@MAjFsvh+8ZO#1~csf`%P|u;oA?UUMQ4TU-c)8V}S1F9I>dhd}TP zAP|0M5Qxu$(36D`2y+nx;w8-1%VG$G!dV33?l}aaM*@LhmqH*sq!EY@G6=-6ECOL5 zk3eK8AP~P55eNyG5N|6Z5N#I_2zpfn!a)szD7}b4?5ZOWnwkj2LoEbiOdEj^(nTNw z^$>`rO9%vo0RmxVh(Ht=ArR}v2!yf;0ug75K>RX8Ah<0M2=6Nh#3xJW0@je<2J&Bp z{I-z)8sxW!{0@-c3GzEbeiz8^3i;h3KMc4jPsr~D`Mn{(59IfS{C<$%AM)RX{DF`^ z2=WI*{#%eg6!M2b{@aj00`f;f{wT;F4f$grKN9lagZ#0O|32i8gZv4QKN0dLLH-Aj zKLzqXg#3>ne;VXZhy0Hre zpp!j^*846^{qMT(1fGKOqVPLcGagfZj{E(zZ2s{r64P_8eFa{(e&68dtkwAJ%S`dj z_YuSDcs3v4_Tn4(#CV;g@#xltMuEt-FJ-ISmAv%9Ht#>Yktq}k@IT$CYPc|>eXCNv zf+fXWK#RYE2UD7{+5JQp-uu4-bM%jjUoU7 z5(x-s~CZ(x(Lumg=cW0k~Va& z%pJ^$&sfntPGqViyCvvR*8K3}ILpUW2Q?>+*_u;|&M7SfJQ@e^J6M3;Y^<4t+KB?l z6Apmi1cW9$K*N_IX=NkS*U8}-JPOkX2n$emSb#av%?3asn*l)LK?@3$V*wtZFlh7) z77vvKDyQKC643qM>VOfB5D+3w4-30}ig1}o9ddTZW+ZO;qh<6z95@Q7e123K>niz? zQT2TP_slev&Hi*y&XNA*SI-&STY}NOd*WP2h-*EW8j%b5v%dM1g^nek{Tt$&D9^Xj zi2pPZE?&OZp}iEKr|Ks@=R9zl%5|>I_t-2Y@NpCE;kXms6#6mrpRv3-=;g} z1Kaz4;$u)8Xs=Z)z!Cz`jc9B;q$3PN10g{jsKy~7;Soec;!Y4S&_DnXFa*$y$AM9R zK|RHykdOm&45_gw_#zsfi3V7>o`9OEL*fs?%+d@Joc;%nQNR##oj7NA<{J*TE1OIr z!E(b@U(-M61~9%&{pRwq;knyr#|}9q#qW^~`qkelw>gvW^+88`oK!8zzb?G_twiZt zrCXP+{&OY2EGJQPHO}KIr%vTtnIU5PoP(VMS*8Bl8rWRbw>khcMqy^c0bviIadngU zBP5D|h7g1n$N(vDP~a0g;Rdfx0&swy1cy+19IBas-X~}P&|3-6C;sUSqM=4s;Y%2J z79OP$4VQ&iy)OCg!zN;gzl7jvo2c}OCVIU)WcxQP zrtL*^mh+S5_4aH}dEb}M7Z0X9MYNwiePK$iiBXk;{Q2}yvV1~#1`EQkR} zXe7cunA`ziF#rb+kq4P4=PgZY>=7_H6iVy93|t-+zI~ERaHvhKOa;(_N8%1aWjHh< zflcZeF+%P?sP5{SBV12s@j~{1mjDCS@fzFYk5tB$&!+Jy19xveQ|?q5;P7d*-P|%D z>oHMvCe32!=yYXyCjTZx+=1da!2b#h$)=s5A%(%mmGVMQw;R&Tmz3Te-KqW-o*!Ue zaPgZwo&fED%|(H2Buse$Cmw{w;Ewk$;=r9s5ETV!p!fif^nwKq*$A^59)rRIRe;Vr z#6c@S`+z?9$}xNnm%(Q!EI>A+`=B0#)DhRnOx*0i~Lh3UjWT|%)B0g3=t2*`W@CgDGw zp?G~uX#cg{3Jie{AgA$Kk-9r|Px~8v5J@`gr7UwFL#U$5ogR!d#5A^_pf*b1 zu!D?>eQJ48Gd_@|kUdb%@J79OafPB*GcIU8Ge%3@cT%gs<#(WR#|zHT| z3e_JCaFA{XRSwpGC>p+rCbS!50JuW}rdhyhONX$5Mx!=jFxXpoShk^0;wO(#NGuKw zRe*;JXW;o8NI+PFRTzn{#1jb9@CU3S2{?kUBfw(#{>KAl|Klplh>fv#b)gEd{-|V7 zFP&kg8kzSZ0KM4Nm66^3hVfHjeIcg9L#M|qNg(s(`SVX&sh(5H{QaJsaY^_`c}B>g zdg9kf!EAZyJDoUuZb-`zL-MPn**|@PA#)x}%yuE!@)!&Zos*b2hA{yX#|aO52OQz9 zHet}^=mp$qWD9h+nMvGE;~Elr6%wx4t3>XfsA3u*o%>GmIk*X&(R6#%nv)u4&+UDxMDJI*jBCfFWE{^%j(B`Id&fk?nqS{H z(o55uh~TTLE#Nn*4N-~WsRYnOAR3RE1T$!CC4kz7UbzHis)o`+4+Urxz~XiS0p1J^ z<;0-j3=3Q6H6)I1lS1#Q40;{|#t7qpz!%_)Y%kYE|G-1T13s`c$_LNSpXQZ zqVAd>cxB_qrx)`qnW%*?G$g$ErTjOo)m7!qt8jMn#j4L_Mx2^pM}P2d#FxKT>X#?z z#GJ*J}gL;FHgHJypG*EQO0vzrvC03P5r z2{HRn*g1fjgsB+00|IbZH0C6+W3Z49HbH3IG-Uh<{Rw`|hT;OCM-P6Gow@ z*1?`bni~{g;+`rqPv&PR2tF9+aD7Yj?$j7Cyk>GLZtM7B zUR%j%uFoLBiAIKv;UI39GOGHbS$0)M8wTK@;-O?3I2;NMmLMB+twsV0OcS0USD+cu zP(IkZ!pnQxn9uA9A$JW6thr+?~jC_zjXc&lvB_NMg(I_;ShN%JvaPZg+{um8#GXU!dIk6~gGqwdd zH-jS>LmM#VM@{ZvVCq4gRAmh$wpfiGRHCu(tfBa)HA zW^ZJ8R(9{1PjAhway|G~)|DD>3W=T9g3sGy+>CtkV$~g&;df>`f2@ zeGmgSPmBN)ML4*KL18YSFjyFFdB6eWe2b(Ay3Pj9Qq6v5c3W-L;5JCZTBdilY zVCWIFCYdz|NHE`W(*AM&i{$#+|5Yld!*ky!g7;h6$nRWM(E&7kG!!Fg<>4g)?*?=e z46i6@5doz~Zv>UOoxm=A$x$>Ti+{J&+N&UCzwz+Mo^BDVm>IvYOnn-GfTMuSj_O$a zQ^wid24~vNM^DMofUc3^85q@o;e(Cds|1a(?!f2JEChhBg98-a(tZyXTs&}GqXYCG zpnFb0$`*i(foq^foI#8#aIC;Ppa3e508fONGksVBY&3vC5&}tNgP@b@B1bU)i@8zzmW29Z zV`K|4P0@mRf<<4t^8?aTt^>u?7Xw~eBQ*TnMRSZIwU0!#%MN32%VZJaX( zjX}X+0(E@=7lX$+1N6x<3<^0@3pD5^spVjcbpBtW?uR1>XNy?jJDRT&n8gk9<$GJJdwihx5F!EyoSy`zAD+`ynt3Uw>ix&zehRto56abw99R&`j z0srDWsTu4|;_rk54KUNY0cXWZLKHv(4C-mq&iAWUwG9wG2A zQ9?-wUMvdN2`WajBM;YnDz5_AS~%cJ1fO@oUt6mL-+4P z!H+j5zzG*UjT=P5egKV2gQ3uO(o5h00H~V+ngswZoWwy!B-n`}ps|u@BqkqrwV)Zf zgiM1Q7U+N(I7!*#?nzPLHj#8njNGtp*X>~m;Dm_ve{J-k{(DN-wZ=_1BU-z^9OLa; zt41Xs1$wW4C^uQl88IHTJq+QTwQsrm+QC-%_m@m7j=@<;Yn^W1?#6V>57r6@*3_ZW zj7X_8%i%<8XPqa}6ukp6{%hMdw~MT&Zx0qnqM^h~pbrmcsXhYi*s#DKBEZPOwBGf` z1%M+w_60mJ3iigUhei|Y8FHq>cA6@N1++_f!?D4}!?20I2jR>;@iYyGazxU+-ab1N3Z~8XmxToG=Z23BWRg#?lQ@`yGOC zXEX{%N+qTd3;GDqTT#-9IDo0yAP|YWz<%)%Ien5(#!;X@4_65`2n1N9*yP?(Bh>#T z>Mq9g>F{T5WU%%6L^Wq&&Sb|>@7D-j*N^h}dG;ukbhm1K?UEZw{p+0Ci^m45+Eb@H zcg>7yudu3r`%6So(zt3d!u?54A++;dbz4z4*!h88ZKJHkj<>++m;bt3Y_Bqbe+y<^bLT9huNipKMp7^_8 z=DNYtqveQ;&Fim(?)$i%`@8&QOH{EoLY}-7W?c;2?8ztKk$7khEEZ3I;S_~ZgjbBf z46K~kJ-PyBA!k@*@R;MqYK&I4MEJ~73*4(k!!2EmYcD$vIf}+^ZZgK4wnd@=@&|y^ zQZB4Y=t_Y91CCKMM<)Xz-M>Jtue4^#FQ)K$-Jwli@M&9Ry)=!Z3F`WI#@JjgZ>+5L zd}Tl-Hue5a$xcWqB~Ig|HsWl&gY1nJ?+}*eS`VEJWuChePYj$5pFG|_#5I{EAy)+` z2R!l^9x@kSx$4;$Z;q>@GpAlYMBz2?Z*Uu66z^V>9}OK14|k6MRQ%db6lla8;xA$p z(e=ni08In%)6FxL&{hN#9F7?ES?R18)$r4B=LiQPj_PrZfB>S1IE0XucoYf+dl5b< z=y+%TmncQ8eSEQ@H{ty6R%%HL>z(cCDB^ai?|251LD{(HQ`Kf&&%$;8$mz4q5F$3t zF|U$dwcM*o6v)2Q@m~8{j;BqpSN0wF2ffZzuIw+GE5>#BB9*z61^Y`%nqz4)G|HML zkaT%8w~=Th5)N}n5Q#oIg6=X2D`lNj^f7EdF~_JnIwnpbe6$Z92^^6~Y#}EpK6GK? z@(%2;QJ>HNvjp1+)DZwm`#9KKXdhEq_~G(J>0^VK-A>=%Dyg}Lyf>9@1K;yhXS;lt1%2VVlpoKkj_>=8Mm z?rr%YT{m5jxBgU>UdX^zAYkrKsjKjpbj!8w{L`N@O#_*e*6O!sN;Yt?h{m9!b{+w^ zBMF`5q)1y-HhynlHnPo+c|ckEssUj~TkwpLGP*bBuve2iGmcMGhQ#zVV*Z4j8T_7wpwx=_%S?JkpyWa6u#FzF^8zU|$@#Kzu@T>ct z*fnX!{;zuBs*Fl|Ehoa(;b0>Tuo?jPqSBzSmEmxz*aygbfJ1|jgHbGKK`)`}e&Q#? zVh*7_Cvh=2o=QR^$`fF307n2L3tBLTiVjDQK+!pJ(LnnFA~w1hDhdrkz{#*g|1Xed znW5>Qqq{;K+OK|^)mEEWh^MtF+PoE1k`Qx?$jXt|kXciZ7?WfnS`_kcHIAm>rx8A% zcggOdNnDQ$d;0UcdA9?OQet=91GQh%PY6wm&NkJJG#qt*e`@lDwzyI)Z=~)dqs`E9 zPd#CX!NivJ7LU4cBJobQTC8@DNa!v{ zC^(p7aLAcWEEc?gwu5^^C?x7B>ZpaVi-d+-Lq!7+-V94CAYk|5$<9y(_`^EnRSfv% z57FTbg@pBN5?)n+`~M;?R0xrOv7WrsyhrGM_A74wvXk21jIVJ=QD$Atm*4IVZZgC^ zcqf{yxh*nns{BjGd)TL=sK|VoHqC2L%8uC7zCoz#L+{o~cU!@)`kCChJw*$Y-s zcwx~I4UJj{M?pFRN(8o0l+>*Wx3HbN^D9@QEhfc7&-ZwFEwwA2OHnO43cg+xWSD>8 zqz4GDKfM8F7{F zs+@Ew1-@ZTQ}W>E-#fJC@;Yy(wfFtfkCskfZXhtJg)MY@3BA~!=A9TBLJeZjP3V0;l0KEb-DjW_{c$^bV;yZw@k~s-K z3Gx9(y>1Czxzty=+gy$TFzGd;(9r&8iBvev_CS*E0m86m;$+#nuaVx`# zZSUt_zOV27-`<7`>8!ohv(~-td#&eOcRHqV|8tCf#_law`3cJEZHC*fh)H~=uh=-* zE>E-Xn$p3arC+o0qN9RmS+v@GkCcG9&uq^&|CHELA-EWFFirOTX?+vhRmb)|-=kDV zgRu6b)=PuEb>uH};~>BGlK}D%3Fn?gI71*dSpXatGbZ*^AS96l`L}2~oEzZ8!Duv^ zL*tM+AT1*3X#Ye~U+epEg2e@JB=`TMpr;oW(U8m|P?!h-tPl}E=KcTa2pDkTaM=5@ zZ|=+XZ97-MG=0@QT90!>PL(Jr!owb6@8LIjE1jt|C9T|I*aU zuLm4uKVL35n0R6#9(E*a$gAyf@eT2{f5i4ZwLiLjX!6Cl8P{~jMSQsct|~@ksfQe* zb1Ci`d1aJC0Rf8@85s4n5on;Koe&AQ(yCi2C}ZF+7O{81kwRc41cFIPXi0jbn4UKA z3C>qLRH_PN=c@d0yagSi2Pp~~eTHb9rYy~|`gg1nF8=r#bNRXC&l25__uo$P8J$&e zb~ko2$T9dW>#(dp9LGBD8K11|`jq34Zh$=JpHj%!{KhVH?W&$!N%`Da!+RwD)}69Q z7X9u>lih88Z$lmH{B7%k`0zA?i(!wgh`3k$2omTWGnE@7U9{#>k4vm#wt39v8xy8XqTlVc55Abu^R;k?qIqq%&8@&Ezn#`D@Vh45=6N|` z-JB;z7Hgs;mQsIwg}sm=c!(t7H8XHzM5qL6)vzdt8KST<*+`NK!V@>bT!VPdV|CXHophiPZE-|OU#c zbcw{ut@_-P5lb>)IZa&;Vt_|R4na_f$u3B6^iR-hD4qnW8AXRN|I6doij}PK~#$TixknDs~gQA5Q4E`zw?5XtZ?Zy6=k_j8;rqg zFbC;5P_jAX=w4A?6Lf+7ECJ03G>^<*d`vwYf`SYujR5Ty zAru}KMuGf+7{oN?BZ5Trko6ER*%z?v|1Z6!@Mi;0*3MLDXWIAtQn&uAn7t?B=e@Xi zknb5_zidw`o+`#^CO#KbeWBz(&fF2x^8B5o<-{La!O0z8W{<0#>3vCUPjia7eqQ66 zdtYa~8ee-$^QPjjy2N3HBY;b3Em7etpc#pTY`gz{Ig30lSNrSQyQL;EZgdEasHS>`6e549xe#K+DEqr{bUtwDdO2vs6A~E` zih>YR2WJV1h)`(eb)NA{AV}e~H4$A+qb1qGY*a^3Xb}H_BOyM7z+WuQhv0_RlR(Vi z2pUW7qwg#*k54%?1vR-P0NeF`_2 zTZ6s(1@mhpJ_@8A)GFxd!emF*S)ZHC)}F|gel3Gt9v&Z}y>4>M z@4>_Ac29?PN``-3zrg;{K$>m{zh_lVS%&qEjfPMA{dc=BxzVxwTVhIL6#?2Aj5<)6 zU*QEOBC8rF1c$U{xNEe7>OlQ~n@GrkL}f4A0kMjJ%p}2R925=omKtqDye=jOD>t6m z3nUFY%C^%yWHo>yxNnrOAKL1JpdPaQGGp?)#D7LrJXEQ;kQ7-__xW~~lPIQd>M!bg z`b^6&hg-KCI9B#OAxe(?rH(ZmJa>~w_jW(=QA{Ri+Hh}OeM$FAy$4N``tkdYr#3Xq zH!yl(@$;}}|FPPZHxZ{|qrSx3&%8ayG_Yn*vH(R2DN00TkOVx|I07h$o@}`BoCv3$CV742v8$w4?cH2mlXxtAV6qU0tR2xA}>G9$t) zyonU}&WqTDLh2FGR88QIc??lfghpZYydC|fMlnNO(=kLJChEX@(8Mu{O#VNkLhh^f zUbt%BshkjaYrpc#^^TR#4(r`*GId;Il*ezJ{vV=?IXpIJMzj`0P(J?)chU(F4l@)!Sk zqvXWmsq*%(((Lx%KPPs0*kfhJkIG-wJqwI`vVPg9gsD}JYhN#>w6oA`1@m(*S9I`! zO=aHMkpX=PNkRWw+gBzJBIZYwg-_c3WOTbxrs)~qK!zM@ho1yiJ99S;0)}r>Xg@=U z7(_g#`+GrHncAZUho5iri&g!AYYpkdI)Ab?uXJ7Jx2cK8}TVsQeo zR09++?6#vm$u`mi@wh`SS4Mh^gxAUMNkK7p#Mq|AqN5<`$hzei8Dp@G|X0w znKkY|v;6M7@%eg5Yhl}R@~Pt5raMnI8ripwOP?ktwmNNpcsRkfEWG#ijY3k5&WM@C9<_9u96MVYNT6rSDNdTqMq2~G0`UMhn zCnqhW{1#|5c`8j_YmiwoW&iBcOyLk93B0FBG%E7p@eqtnu!n+nfyBu84%bqU<_T0> zfC!-wC_fhH0PKY9>lXy7M}SHO00@J}X#$5phMucl6iyQt-p(6M+T)gCv}u~_Zu#>QLxY3L zuMdRAtd$zIZy5P3z4ybigd^AQr}bo*H0TFUNt-IYw{T70jyW=MRHNBcBd40WRhR!f z!L9}8=udidO+1ca-;)SUBO$B769={nKu{n__KHAZY)4IqEPNZ1jM{OM#d|kHnxMjm zMMyAALP>y{O|hW}CE>|9f^QNu3I`C}8-XGQ$dDuoAB7RCe27TY4mf^IJcsvRI95cv z`L_0AWRghSYn`v-!+F~$Ntb<+BlDE+S}iF(_~CCwU+bMeFG51Eg>vdE{S_8TiXt8( zHN4EGKhMH)(*B}XzxJF?ahf&xtffv^b= zbfH>s4I|)>y*64D0%XM>f+(Tc8k%59q6Wnw5?&;#i>Tp2eoT4@ND4;;QP0vtKW@+r z*-thi#I}#-g4!j5YF^K)5fS-B0Y5A``G2=Q)c&(;->I*hi)y#e+Rp3?I7=;6IllU? z!sAejhsSp8IJ#|SME3j1nO@Z3rl|Qly*0}gzZb|Te>XoHYWc1IdHUkyX}PLL zvv+IMlLr-hrt-7FXD&B+gy+i8C!N2;vq@$h(%|E@T zqAAZ$DlgkmQvo7u4Os>`B8EZKAa-o30wt_vg{pr|q(*BBFrdM7hp9%H*?8#ATns5i z2r0$yN#k*zm*%?l(I(fE{4`gzDRE<6mamlpHm7eKCKjPG`8r=xilxYW5Vp zY6*{uGYRq9+hT6IShnUV9nh`UQJvP=vrk~M`;Pi*8Vj|aHJYW{A=$TR;>BWKTM@{J z&Ss{3fLS-lVWyfHwk_1p5xY!K2p*ejBBPZ*_dF%mWM}E$W=j>h*&(ZK}h803iMC}I`f3NEf zYJn=hWA2T9 zZ2Gp_DxqNGPpeZ62bX;g*i%%Wk+rO8+|P;ri$&v)E&g)ryu+inZpk(Dxs>mdtq;zY zjB{N;9$OakC;XuzxAOz z@a3gFwaCc%Yf9po)hbV;DFhfds7H`YfG(2T$PjoA7zYA6qQjbKmL!lLrAR92~P=tPW@R5VHqyCs~MzDFA0A8o|6LD!}&?<#BJTb0RH0 zbW;{a9$h2YnWUAoeFpYt&vKn()83i)9>V-y>pThRnHZ9!)$z}le$jVKYZt{_YSW)| z`+UJc$1kNT{cEax7Il44cI6J}2DUa;rtH(>pSwJB$)sWNNYNkl_JoreFFnshytBO* z{Bg&Qubt$bQ?Z42%7>@m-1iyvH_urtxB4L?OfqmNY)dd1j}W$Xx-(Qc8lmDEKq?TF zL2SFrIu62Ojdzqlp(M#<7yt+wBB6@2qI?#|!K0%H6Id!UEFL*1!p0kNLT8fepcEo>FmPqq|JuF&*U>lHfdvhlqn!CFH_FzvTvm$>i%ofOQd&Z-Mh z>fzO1Q2oGS?7OWSPXyj0`e`<-9%9xPeA}GG-K@SELX*HtN&sOCb7*)f$s&@3h8Oc) zz-i)oyBa}Lg#tx5d=S%CT!^D4=zW3sClG;Xyo9FnxxXfJLcwY;qsYT%HfTcSx;2wd z%#we!eZuVT^X&gT{n`3L(@u@A+50H%pVb*@S>BKB=C63`+o)%_oU$@lpJ!WrLssof zRrUEzk~Sq7b9n0VJI5Dv-Z0%9`)sOlqw3sQqMajDW@O8*rEe`}ojAF>iKE;$9F%05 zXDweIKrGf2+-u%(N%-mgyFUlDQ>7pX88C&RlR=Y7Ml=htjT*;(0RjRziGJvnaPS~V zhU_{R-kZaKx&>jMeAGlYWXyGXv-b zJRICJnJFf@I;v7Q8H5Eo$?-_!IWK-+D`!q6pKTp4Y#rYh@?`())_`As;=;+4!qn*x zkE}A9HE+JjLgSyDnyINB8k@Ixbd@jZlsvkO)9<-CwSGvYC^Y`U<>+O*YP&x-${8s5 zUb?!dHS5#-j%inBTYh!tRmIm0Z%z)(t$B}V1XDd=lP}Ez>w=<( z#R-(EE`>T9uy2#3C{Y*|Ze~h?qp6=FhBri(UgDr=eRUQQarI9TmhWLL0-2Pd99hU~ z$T2mN(|`q9%0Z-vxXRMY;&pGU|4YDrN8R?{d7kTO|EIzv;@iUh<y<`w4hFVzOqaw*1{CRCp$ z>TC1&)$C7f_$YSLV|{C>Tlt#bQpekGj5x)m<8?gZ=KJR^CX4QLTiu+i`ljLBXO%e5 z9r5>!No$it8DE#J?b${7nQkICW+?dn#$!vYA0HEzPW9)#zxmLw!+xEC?)OnL0s0Ms zfMBd=p~YfghL+5RLj;`$+XXKkFFj-gA4LpswfQ0}%}l?@2QaShsHg-hk(I;o!4ZQ% zWuWGPmBMtTu}lwj7*}=JA?2-GN)!FnT5GE zwQ3ru8>+noD)87Y3x^Z@@6rQB__KlM$%}I5?tHU*+t?6yP$h1)e|B!xxC!xjCm%f5 zGs-SI`tCDq?Tf*+6|9?|uA5)qzO0ds+E-Woa_E!KmStBL8Rr@vn^loqMkl579*=I1 zn>;h>>+GD2wM7;lR)msqOBiQ~?f$(B<>aTBreDaEUREkQGJQ&Q6-WBn>9jY$bJP}O zMX^4cH_u#A{bO$G{5#5WFrQVD-vyq5kw7r^FCfF>dFqfpfWAT)yhRdX_i%+vq!^m! zA}J1oeOs$Qkqm)jBXX(E>S#qH@)Zq>$-^Ozz-D630v^n*LU)5U_CUjmqdfO`PIzFe z?k1VYcLkd!+I`&8W4LEG9iz0n{^HA5-6Dl=2`ZPjS#5o1(ENXS_R7+S1&gLJr{6VC zvB~-^`(bsa$_R&uDY-JU+~>i9EuPam#cJQ?@~ZW}CJi4u=5tcjJM{;)eW}0Ynop;{ z1+Vp@ZHua=UT+?(S$;ftf8vGjlU-78?NGTLbh`SUr}L|8n?Ai1jhNDb znXff7&V^_DA5(s@VP3VejZ3DJV8IejfOjU>@l~HvgcyBC-f~p@=lK4E8wUFbmwK@f z?~tS4&-^xgC}uIyyCrI9cE{0i6#9;USsO#TuyX*v>=zA^BElD^abN}*a3TeKBCmfK zK9vmZ3W?d-0H6)RDf%j^#yE=WaX?S)y;V>h07eJ_O)}{ShOQ$p&cxCiawMKtqWWtx zq*yoXUy2QU^5BK8;Uat-QL2+L;cNFZ>cSgag>_4Je!T3imT}i*nmW%u@s)Vm0G%HJGr;lKBne7>pwpmDj;(`635t7PSOa&}d>nEUNM zj4Ht$eoe=qF5qAakz19t5Or!<3bN;_1rD)`XpF1zIIC+rJ<@dNG~$SF+8C|)F7A8-C5bS1i&HPvTagt6k%$uGJj zI^U z<}=tVeGbJ{lNN^^3kwHK#)30wuta z01^7UfTj@l&z5`EoI_dGy4~)Pm%dFHCy}CZM!xxYWzdr)X1c{%MmEaEh0i56dU5^O z0g(QjK>FKxyZ!wnnK!WyR~$Jo$db{5kBL=bKegqTh(26#UU1@>!?f>)Zz7Z@#gt!o zTkQ8{>JhblX$dbwKR#Qt>&(bfFZ^V{hEE?4Je)CgTb<>J1u8vT=Bc-6qg9f>N>@of zX{?PG~hj)7qtI3x@(A)3H73%0?m0BXkjc4UK`n> z4Ztp+1gjyFV+G z#nc@Ml}MeoU~b#XI*VOXWHcw=w!HJVzwrOkN&3J#%?b0&dUfCSWmBI7v<-Jb$yB=M&7F>8q_9TuF5i|@b#20uWFpP&pQ0-v0pQ_3S z#jLW4jKk8LjeHr}6EQ_FVUKBJ3M@l~P|evK(2oo%apt9r&?`Rp27mnt82a+vNn zSRkWjHfdXq^z^@3>P(cP$S-~OqSGY}neNkVy|!oYZjKqVxkyL3n{ z0PJwl5E{UdOS};rPeRBFpg>@~in9giFNIiN0y;9N2@y3eXCau=mr223NvfK-sNZ<` z%uKu=bwOsLkjV}7M{vvptC_+5E2k@`s{7rRl~WbUsrKzmtDN02$myW+j7t*Cwonff zFYB7SET7<-b^Owh>eZ>Q;^R?_R^NPToI!^D`jRzYu=k7VPc4k&Ov<(zzH;ipV$<=N z-uIeDXJ4&!=UwgHr(SQH$#dKP&|-G~z}lUHpykXix)$LiA|tT!$#N`IZp=(cAqP}3 z275GHKbZv_N+dH8-05l%oEJUB2_AOEz#7&6BuNoawp3Sr8}`M3({JD_HG)RUPIARH zrF;>EHOkAuqhf&|*}o+I_v=W#sP&}-q2Jw-lJGnCr#aSGixrl4Zg=%qm+P~boFT2Ka@tfWFg`6J? z`CAt1MIraT0^U|Dk6%-$(_0=~%Fp~R(P?HJ82Dw4#H?Fa*E=gF{wYdH&UEHXm$J{t zw;dC|MTSLhj|fgzb3OJsx7?}IdP9os3VJA2r!v6$qI83ZhyV;u^~X_6eIt}FmcR~a z>q8-K52Nb=c+b>o{;E6(K-Cjr_taek1{OvjYeT^&d_{xJ-3kno4>>4j+Dse{ZWl$& zpkWJ^ZbV$$iE^-qB#SjDKzjiU&uw+#ZS}r0Ih(T;lJC2yZLCcV_)t{8Ec^GPUHU#L zJ7ps*rtD97(fhG*^0LES$4kT(RjLJiOJt>V_AdV6prkf#|6j|1vR^9+y?Q051b3sW zV)}_Mrnk6d|&Iip`e6&S)z`)rX}W%m#y1KKM%{6pVHswijU;3rxpWW$Ao` zN(hzB{Hk;T6z!|&1F zB{}BH^?I+yO3En?K3yKG_Uz+Z!z%lrle&|RP51p~5uHCUBYeuFxz7ac7T2r_CmKC1 z8o4xDXZgX+s5^1R#_PWd!w#Pa+M{ZmanAkNn-5d9*A!n~rxxg6pq0A+)~8Z5g!!l& zFNF7M#1UK?1Z(gJ-$gYcERu(r@8r-1^RX%RurW{}2SBW6Hh{C5Wk!%+at7lN+eBcM z@~~8(oIFT&^)~snb0V-hS+UieKbW6tn)UD3x>08TAlbHuI)`of?=5bu`KqeR2J_bDFwKMo{+@-o#i9O5QFUBV!AZQ0w50wi2~-)*evXux)<=R$dN@gMKvsmLJ{o1f|s|o z>c-0J{*_~6<%O~Gefut_gqBRIu5OrQRi1`%zRC2m)>E^M-@QrC?Jkn{Z<(mQR^9bU z5|TE-+fu9KD+S8iEUzn_ycIb4>Gjj{TJ3FjSkLwEW`AF)(Kt2uK=a(>hpHcR(tpPf zywW`VDr7}~9bypSI0ow}SZ6>~7mF}4t}}_4zXHUEtj6vK!Z%Fdmj{s;hl-#&!5wCJ zF5R4_3{o7d^kR&LHp7etiF(=YXtRX`swqe5I3a37pwST^<0IgOb;S+YO)^cJWcs4- z@waIF(6>we(jh+m*P|PK2lgFR4~huw7*3d0K5(c|emk}5`F`)8V?a{q8;$qHeK0U?mxh6ZQf&r+) zh;Bj%9L7|UT}_cpEz=o+C?ZjWe19Wsv%C=w>7XlXNOXw8(sUFM*^M(;sJulH3*9a% zksrayg4DUt55X8a>{QbA`StmzsGrJ14tQ=HfmELw0CyzaQvnG<2&}{Li;w^Q9VBn< zLOinrKg5$|_7HIx|7w~?ba?Kp$kn;cyA?67M6YJ=%B+RWjo;tzAOFtY?D=joR{7qf z1)tWWN)HrM%k7Qi2kmh{-aV9-mSc09IE|&vW zbYa?hSi7<~=-9T<){&4V{k6ux28`8eT6(bmd*ejxd4~kllW-W*R4VgXvuC1-eZa{F zsi_XR$Jl z7~o*itaVRnbF9FoliI?Q+Ipr{~C;OMn1 zJtF^{xp-|_S7`3uQ+f7kwcUG7jP+E*`Jelz{@qpm@tcn~96TpDc>9jHPtlTV(3UO! z(NZ_d$9adcL6Y*R{8^T3jAoTAm1~OAIyf$5Jije_!rc9im(}xXWc?qc_j@`omgM_U z_alD>y9Y_-*Zp}v_$x?pdT?oT=jW{zHN%YA5feqb^2|RAP9}jlBAkFnjw8IW7ZC{a z(bpzm`VzEK2HUJ{M2?B|IMA~MmLiKyh%mxYK8^wr;t}(%Vtixu5e9sYa>(z{wrP4@j7nL9^PEyeP%}WILjqfPH$bLOKrS|-UTkQ zHQ8(MO!~*~>IF==V`k)mGB;R!>|R|FU}3xWAb^%|I;!|9M&6Pb{>(w2qu; zJiGa+*enTm(;2^97IwSb$Ul{84%Agx4H}Lh^1&4NK|tmQ+j<$0IYkA4;|17Wd8r73 z#2od-Bbew>V2YZ)lBmY7fy0RD$k8}RXsW7GR1L!3=_rqYt4l_Kgf~J>MSvYe{S;E& z>k486XZDhK*2_rfWz_fKu-sQkH{Fam2KPQXD!Uv{UjBZ}{ zq~yWJ#NOZxRj=a-x#X=LYI8=3&{%qVex)nCVa&~$Qzw4O-&M7hJtMCunpDMP%4TiT z>zwAm>;J0k+;gEmp)ssu)rM;)1zia(irTOB8r8JkGsB{ zs{Pk9?n&h-2EFZv=tOfMl_HYphnsD{sSJE%jHT;EhhTCVK~;wQ2*nQ42XH1>v8-yF zg8pL=7K8}Lb1-##?53ql9zcDZN7iG-O4?BChr>}5QxOSx1ll#WK|$D{(6{YG#1(Az zqulz$)7zxBI9?s(Gis=PC3L7ay4~JwYHnZ(3ts*Oh9(_cS6^;SKP5 z42-b(+Tw^zou>_pFJnf+W}FJ(LM>J7$rNRRj;JBSFe6Q%+zSrMQG-MT)?zEpQdqVb z)-H?rZxbg6v3*?AGs!ef1POh^;QJ~|>-K5rK2v7DvheD%bkmEKk{#?d(;#|Vxbrs(oiNa&&jf|wHX~eRR zF0W_UCtpJJ-j}Imm8w3om7MtJ`5Ps=kpw}2^c5jvQ|@+S1qwQsw&r9GA*Re3ayiCf zv0QfrSlA5n#iTv`Dmh))e0}a`9VwDQSiQ0wLP0s0s-icq2$7BOROm3kV?!c7P@71k zi9J&WkO;>7l@tDz>x+(GtgqHHd(wFKXP(c8@O~#9tAhXpfSkS~a$-bHaM_YygBPv}HG(8Z5l9F@u<0#q>>^k!d9xf#vm&5YIl)lX#<Qx9x;G_s_qmnqH{E#-@RRq~0OyF_?d%N3|9BOQYqh3zH zD9~{wmrT3%5k3wDkHTq+V6rhQY0g&(bveZLsJO&`jMV)#`Cq*GW!SGEVrLrm7^Mj`iw!i-@9+DXjkV8HRCj@xt9-(=0< zT-+#eN(4h8Ij5UMajG&xN{h9PT(`pn2>Pi%MfN~&n;6H6O+T~WI_zH9{H2cgIlCv288S_ z!IF(QRN8tehVjMbT8KwD!cv^7U^<8~))LQwK;3pz)NuTkoX;cM2&=FDUN3i~#VS~5 z#_RMisjn^!y7|^s=PiHlGew0uw;!>R_JXo$3VBb~w{5Z!SE?w#ALX5O1J7}CrG60f&4YM5kc(R}Wu^wv#mT8#tl{|Z z8M2A>EkY6GG{C#pjsMR-59yNQb)qY7ig%Yi<%=X0i7$7Le)E0q_D*vmC%PicUDG>1 zR(Wx8ik9ih{UiMMf4S20%wM#72;awxNBDen@Nm9-rfi##g_dFKy9;x!D8`b5w=BbeQ^X8gd<;gjWkOF zRH|x)(nO0ou`r`(T~i$H1!Q378EnO-azS`PNj=;(Tzv#;Firy<1qmAh?wS8TgEDe# zo~P#c-(L0g=BwT(H!kbs-p;Q)=`d;6IQOu{4>qdA%-WUFWA~~?eUnZqabUiAv0VO? z{5kH`nNugqsvK(HW0NqE)w!wt_x=yBEBs6QitCk^J-s(|-4}=INok+H1k45HM1)8X zp@+d!L1TCMv2a=84?!W0YH}gvcA=)nKplZ>$mA2lzAOT>&Lb9DO}PD~?tLOo0*M0{ z5AOP7RdeJy#hALZb5+R=2H`a9tRp5F5+=$0q61T6;HCea601pL)IXPD&(e-OQ0g~# za0vKxWV(*Rs7r`@+VTf+XC%WGJg|xK9f_Sr)L2YEF5>T(>UfngeC($E;IZ$koTp}v zt{Xb&wBJNQ%IX9^PB)HuocyWgkBaq=ARW5{Td=_d7(?u+f+H089^jhDx9bO7jfJ78=@oK(}#Fd+Lc29E}3SO&6iDxknaa))(Y4s)z9nBhhG; zFPJ~L2N#iSV;wCTn`Gp0!v3kD82lLnN$Hug5O@r~EA}?csdJMq@87X@^}IhbJ@?Fg zdQkHHYS$V2xu2rt{toq3{BHQ7IKA$^Rx`cze1Xpds?Aq1pYux7x$@@BF8v;}np@tr zQ-=MtRqYk~^mVGspPGAiI`%wStQ*rOxe(yTcbdamv^}$ z{y+22&&P%pukL9(osuZ9UZR@6;9~BBH!T-ZpYN>dQYp@EQJAk0bs^SER?0IVJ;0|% zPpNX&sfS_#(;96iul}vI>Da^Rw{xvieYE`RujEc{W*x6bDLI7UC1=boiK{GLj=YY_ z;EH1F5O#2e5pNh}594+1s1p0B>&6lUOFSmP42FcT6yn#gSZ#G4672HLzk#V?&W$XY zU&Qvq(S!XyoMwBlXDi)MNfv^6>7ocYYyFQ)=JXC@Dn8gM3vp&x^`y4$Y%O4O#SMjU zw@pRt;LTeD*&4PxB-Zas6+EA5TYe7Bw4yXJPOmEXjj|dmY?d!neqp(3HNGb4ui4E| z#j|wpjcE? z`XDD(?f!9(KDR_UPWg9PY_5@{y~gsEZpFrH?$Lf`>P_0W3vN0nm_6|MHl+-0Qd+!?@KNWj+l7i8qJBM{VV&f%c z;YJRi2G8j8&&P@~6NA2MGzY)+U4E(XQg2mviKo++$Kz~+%FYUBZoM4S)MKiAY04v~dDS7s;oxrQ|jf-_FAkljFV zPW4@lP*4y;>mbw~BbrYFI)sZqX=J6n$t6RJ@@# z=l0B&G6Q_>lRtmp&7xI?VrRuZ^~Cv3t!MBZbARN7p0ql&dqnxXOCsN9ycI`m(xpif zVw!#PIr_Q_cgc;t)dx0wgrhGeAt5Fe1@ECC#TloI9fc2I9A`zi1`^)&LPCG47)MIn z8Ll40bYU4$b)q(_EG<-)?hDCWUE-ZBZ&#tWh>f3g$`eM;NYmeM@Ek4FYJ*xM5&VALiiHO`Me|SM$-HXS0DdfX? z;-;JDw_oG!V?5Q$#s{xl!Wx<4^{E-&Ess{XS*_kqtSUUEu+-Tpy+4ZNe7(H<<+zWB z2j=a(yH&WMHL4xB2Sjtjl})K^KI{qP6#-L*?ehSo4Us{x7>33!&H%a#RDf$dY_UGf z91#LYR}6Y@a6pdd%LZX5)i!muvt$=d!Fy@Yg(wMb?kE{U@Q6OWcTx;pFDxW^@vV>6E#OFNuxztnnhtCxpZf~CD= ze*QvzO|2*S7D3mx1sJZYm(a62qV(w5l-Nr!2W1)kaN0P{Z~KgbHY_~UapSM_2Udg# zh9H1mC0G)f*~-!FBN5!Y*PXYBU;}=HfE$46WE#P$E7ozwqmd{|9zjiGe*=&XA5>$S zz$EqLf?kk?E(I0{jXr|%6=rm}^6~hxdT=ge+RgKX3JAnfiVw@(- z%SOGcr$-1^+)uwR3-R_(Gu(M^+{f~oQA@#7?NI-mD=&E0@Iz>-kJDK(VSi(IchoNP ziyLjtZ8R05cc_NkPtCSaf7HL!>`O^f{Kr*^mnNAE4SL@=!maqdZ7`#-$n}}YVp{{c zEkWjqujkj$9~N<;zi>4X%HtuZE8I7>*lR1PxO`8{dae{;7vrU?DVDlNlU7JH`jdcv z7%^xRAVVcqqOg}iPE;Ivi+;m9me36S3e|{82m*MLU7dgVShBoPea;A8jp*b=UB6b{ zcT+gLz*hF%6ydumeLK%@%evztaF?f>H7^LCc3wSM@zUS*@QloD&-ZAr`*OL~^k{gG z`>BMCLvKni+fV*%DCV_hM~s^L;`4eF0vBFIA6Mxt@6ul}|0o_7x-($0U)#y8@ruvi zn8tc9(X)7eel~EbOwd$D2tkESF~a1vX2N0eW!E>c3_*s$tUh*;X9tIyf+@qXsW#Cd z!uHvS*9?|jg_&>z3-u)k?_s*CusT~QhN#D6q@7vVgh1;_6edI{1n$nGRadKt?{!fv zRE7bJf9N#uq2~S9mpTdnUj|p7@Ya#F8y9tBq^=n_aIim|tdZke!p% z@-0ceYMe`1#$>hP;DHk>v_@TEjHy#ocNx z-rc+X1PV_A7gwF;9;|P{ca*=aj5F&0; zm88FENYWJ?k25!yZPjiI-0%CTBKrNVPR(OF4rv((UMrMzM3lgc5`sYE!G1Z^CIZ|u zCe!|+E-?4K%zfNNKSVc~U6#tHDj{dlhh z9PA6+a9!Hz14D(KV5rb(PChbzw8utxAllpaEn!#yGA&!55MDi@?PGkwc~BzK;9&phW2K43DNWVqviE!shf=Ijzm@6_Aiz&{gEbCPJJw{ zpG1-$c`GlhpB#Zj0~OEdwf7W3mno!JC`_(Vkg!v1Y39RO!5)vcXACWND zTyRp}amc4RiVx?}ZD24%J0QI$4`_h+BV^^Pc`Na zd2ZUX*MD|%lr?^*D$@_S{T#7WwF#{ptn4906aXB1SItb?B~-Q^`1j?jUq&s3oSgWF ztepJ53w9((fn7X@9Y#P)N2oYhS|{KJ7T~$9ICwfv(S8otJm*OT*1KO5G|m{-Q?RL* zdwT3n(R4=X7dWC5493r2-TJfD)^_8xmA(yZFHt12fR}PLmP?snW&oP+ec;ARC#(ha ztOeW6QDg@SJxP^9ImaI!ElgW7N`$#&es_Y?9*ZH@1#j0=P;c0UVoWdQ9*>Gm)2W+e zk$HIZh3lmZr>iBTn-dy5yHdUA8Q=bDiJtqecv05mJ-!J>%VzIw$&kx3O>wibNvEfc zcYlKyw#~<<6OFHaAA@xUTuTissTZf)r^n#6Zymg9%^&~z{XWFzbp8Nb_ZQ69>D9KD zllh+~!r%rz&%jd-oPcO^dgnCc6r6Uw2R?F~9=9k4fqmu7k-0yzVK&E}6i2O=Q&V+c z&UH)8bR8D`G%Jp~C!6phUgLothPJ*;1$)WbB0tip`PRsf2kG{vj&EWLOIZd&`^C1& zJj{FarrHj#Cf{YhP28q^N%*@#Wb?@wIjPxd^5C?Hk#l?6xLuYOMfIdp{Wf>BMb~L0 zwl`&YfXcm(kN^wlmgt2JoolCqDH#(3`gz0x)KuUedK$#ZO2XGL2*$85nlqv4qDp{L zk1ZOFR$?Tkp-P5{OlFn>283>*3ji6JrWhBT_+D9_5L{Zk`>X@KeFs1Vh%+My&!OqU zgAGFgDl{UT21X)H2nWh}t>FBTXW;J$C>~g~!^2>r4DDr()G|5<51HpQ#D$1FEY&*_ z#3gWC0-D^Kf*A&o0%&5cycB`RbHG^=xJYDbDB->{4KhBJHzr-lkT4l>pN8>rEj*GI zUJRo~kO62aU-&r^xzl6ElLx~W3a4S+e93#{^+5cm83z}jJV6%P)ekthv4#ODzL$sRiOffzFq|H~WciwzzGeI=bKBa_`PyyXy}j)4Z_IE2NTR7r z1PC#zz_y;QgU?L|FIOiwduR`_H{c5-0e*rncM!-2ZXvh;zK(M?5|+>ki^6u?*kXaGjZN6Exw1<&D2hOqFpj;|Yi)bkHCw7@N0~5SmJHMEQ0i zxd}V%81h&g280mS<}8eg!Dl~R$Dv* z$f)VBQL{bT_EgV(YTB1pv%K%68{Q+V`Z9jVHRIjWVL8-2>WL4Y1F*aXzuS6gcG;tJ z2VGnZ9|Jk=mQCfJ{9NQpF0mGB@X-F0$I>0ph>TGw$@N+H)CqsxAMx}P?>Vu{X0F`~ z8#yLg8<+PK9 zM_1!XTOLcqr7$fMy~n><&22iqA1W2fp*JM=r&6Sjk2g8gc5>hcexNgZREi|Mdmcg z*uWLQI+mwE4M>9fl#nV(QUTxxh_ed{G`LULLjU>%;Gv&ik4*q|LV6 z1M_=K&TIbMxBFC36l6#kR_Fa>ZIj&A>u{p6vGRaspRQs_G@#?hfrYbKcSb%DUc|^h zUq9iu5ph9YB!^-BI09~BsRg-G?8zkexxW~a+Cp%XWK28!*HK1Cf)B@SWR`nZ=}FAcXUp=FGQTqsPr$Jc$K6}H#;8%gUNCt%`xX&m zIue3og}l${aIie}Av7GkFgdhWKV9#GW5)`S@6-j)IZhT^%yI{klOYBmxEawg9d783dP#lu(^Hr5>qZ zm%cu=8TG7fM6430id3Y53Ul%VC$g!$lUH0+s0%Ouwa!REnGg8w9`Ox|R(u5tX+X3#;(H$K`m?5>$s{zvIfA__TX! z!hVJy=IN11QaT2~c?LMN`i?YRJ{);*E6SDnl){*caO^w-^zCr$hgZfLxN7v2Q|r!~iFVXqkf4F!Tas6sOE6J= zU%lexL#_sdZ<8fu;@Gz&zgbUb4nN$>*b$4QK(DaxLvTl)i?L5nu9vkglNJwj+ZHwK zlv&}}9eJ(=@;|J!h#jb);dL!A`OLpyqbZ$7%5tN( zdcb|K03C888P4~Jmtl;xYU33K5)C>9M`v*CWcP$q_;yb_gs)mGMCkoOQ%<@q8pO9Q7LI-9hcA+_AZxlsmv(HQIq6N)AOyEPTqP%0s(ujPl|p#kY9*ZHrehb5 z-S!Znoci9^#H#XoqHARRle8lcuCYbBVVizpN@YGPEBl_w_l(9{5)6RAZjoLTpWJfW zxXJsa*pJX}{J0qcTP{1R!Pu7A1LS1HkUcg(*1w6ND2l;LhUK!dux6b~3cFOOHBG^b zs5&ml6$AEK*Yg$$!yfr&W&Ra6bw_S_kl|c0VBe9eNl=z4K8bqzc-GNO;ynb9>e4rU zkvsbIE)}m_@*AFgHC=`mxQs@1z0-R7`a7B0fyBJtYbtFIa|q5kGK7@5SAdy1aVQhL zF(*Un^+f{54kj>(~rSW6rkF7{|ZeO|IkUdhCtFu@^Cp zRr-y}Ij-tW7Zff~}-xj7>4ZgtDbflv)IT z!ob~OhFYW-gwEJ>ak{8=PFT%zRBLi5lOT2rLjOE7v%2Hp#82?{GErxd)sq5a^&|-W z^GvezZxY*`Tcvl>-Xt17lTU=uZ)6uH=-;fS@lGw4tq^`8%-OT4fzWSc10~e0RW#pK zXu8zUo7z8R2hkdAF^hGqD2d#>Gc{2;%8?D`oaCr?%wVNqi$U&-CCG{%sLfA&xvlfr z&krI$i>T@Nm&2{Qv4|8NTyS_9rLslh@DLCk$c}2 zllq~~7F}r*#jD{xvnWG1key6U!9GLR?ZP{zOzvL{q!^=42)-$CBeA%Co#y6Xp@IZ! zP$R41G=(8E9SplELEE)ZO0FQd!mg}2rlUuH9dgFlQ$w+1Er+E1MubepYq7MCHw@P3 zj6VTF7&H+!VJAMI z$UyKGAZyC3o|o|K&2I>7`L2|w&hOciF&##uZ$e)D7Aw>kP({mk)ReQYST}CSlcqje zPtdllg*>TRXx90a@B;HZ%c;Mvk@LF51x^)M12qg=wJ`HG0I}I}Ji;5sb(TjnW&z@s z+nD)zq-6qF{O(y}@Vry;*%X7q@PM+&ZKOsZVw=cmloX$)c+l2p#X#)SFlRYSMsC%I z0c$|*i!kPHfrlbE(WhZusk{%R?&f_8Dm$xb9n#zev1cEwmNY9RXY8o7X3KT5`1Kft zV{D1A*$1p$Y?SP!&sRmv^s_Ek8RtV_>MM@w+j`B35~R7&=C1nsPQNxW3nWpU5Y;`r)0x!?Ldxn{gKxnT&<*PVeRt%)G^3&ydAL;GLu|bP5F{< zcdc5}DBmyzgC@ncBYMe*KK(9Uc^Jv4rU<-QlZL=QVvRgIVx>#nTtbKicQhYhk$k9V zHqi4Qu_yE*RI^l@%l18icdp%GWPsoz&o+d+mBf5E{#;*@r12fh^%243QD8-$!P-Ye za--ADwj$2rvYZ7j=_8nMeucnQmmq^10Z-3BWcecZHZvH$1YWVdvbrfs?d(|PCz4%uOc ze>9Ae^+oE2EJeTdn^+w;QOkipaL69YqL-N+Hy#z!R(xxeI~@zcH3T^}W@3k%Ci;*@ zxgQ2i>ZE3NtD+iT(uLQ5Rj>Y$U784)v%a@3kDbnlHQa&jcN%lU zTzSVN-nTV{tK$f_uLO)?lrgqs*ty|agv7PcY7-vDXNvP~8}g9n8ly5FTMjb_yyy>x z!W4PF{Mj6s#Dv1IqcZUmv)X=3ek&R&3;H4H@5doWBmy_$X-*8s#=pA@E3{bZn;&ft z;Z6&QK=*eeD|d_MG#8p4Yhu;I${_BCCUU^R?uGnsW<`{wH5QzbIn_|*dT7#NndCw< z&>R!v^BJo)H1-kV2D~|Zv}FDB+?4|a4wxcxT65j%ah1!v;@x+2pFjEOm#)$B3{EFO z88o1VyK`wgU#$v{3s<^NxwdB@Ut_^a#iEYMBRBzT)4v?SAh{|%sTh^R=s~j27TGza zochXge|4c67?^aD2m99}*cSI;C@k0(B7p$yfDX6r#_;lk>U&zA5>LKOZ8BI0VLuAB z!=cnr;6&*^4~@tM3Me#}MsE8WG=0zy^cT;V7ns{@2xZinyPGF)f9hlV-P5!dbvAm$a)1 zEuaMwGXk|v>g=JkY`ZdlF~>yT#<*3a$VdQ8I8OlB@U&jVFcXw#KTrg6f9dFtE%zrC zBmruiDzHzelK{yoU2A2iz!-tq=m~|<9Yw%4$waiUVLS!7qcA0{l-!QopQ~>P&EL$2d2?>{>u6^m;-u; z%O@-R-Sfd=bH)#B7*H4pAG5yyh=mn{V}x{L`SG=R!VV0G<5X1K6fTN$R3?I$NH#?3 zC2v?O5#W+&VFqER+)o{G644TA$=_#!R1RSg4-IZ|92W5`&!fWZ`cw3~f+( z#iQY1z~9Y_+0%Q{D)&jsm1*Uyb&upj1~%BXUVJYnB5oA`+C%g1_eZ{|Y9vd!uTC?v zT*0gTO1e93>{jQw1FrllLX8CX^8CMD0YbaI2fk%4Ml}@fy;|J zXoMdk=wS`S#4tv>hFBm%u%|u!{m-x#7tPoJjiH=JMqVTY8NrX+LmLT-sK$s}0JdZm za8$vWjzkq&sPD&d7lwpwyAmj!N>lX{Yu?7jrreFt4q^B98hI`l=8n0%`*k3?p{rcd z-*4NxFf%_st0?5Y zm?!IkL$PNi*|Cr?pz)n0@3rZ*agE-Z%%lo+MO!7AQa%KoxrXPwna^BV8=%N;+aq{H@%~Pv zHS#<;OqUnFZA~Wbv$cyzDJi~^vBYJ(Z^}o!h~*_^mg&fKtlRfMO$+!Omba*Ia?yK( z(RsDK0rEn!&?ik|LaZe$)zKHfF}bD37t7RMFq^d=<2iF#Y01Ip$i4o83;AbFbp7_v z&lC>?zk$xdZ3E=NGXfUS4o3j?G)!VAU^ZZYTQ}G<4Az7f{MlZlUTcBL@(dz1`Wmc; zZ+}xJj|wzsM=uUyZr)eQlTAY&Y5=0YDVwtG`&t|$98k);s1J!uI*)y5V>^yd;Rn@V zkE9T;b2Mxu6o^2iEu@o9e;YV0vwu=aU3+1*NUnN7%uFY=0ZV2~i*dUTkOAa8(oE>> zm)yBqM*`UatLV-#-x@U!mJ$>4xY{AmD|$}2CLdsvK`;8V-;LQqQ<{UOu`)k$M!N7$ z;McL^XL)dQ9g5DgWU6*_DtpGZDrqu7DVa^nWA_>OG)7twAMN1>KcG(A@7jNL+JZgU z6cI4fsq_mvciOvtKhJo+on&{m!I{`OOd>C|Au_AHUgLOG#LJ)=%S}T#dZyyC8I1>; zEAiO*r`cxk^VBq&)*$dHA7E+%s}QlfjC61XLIwlXyLtLZPVZU)$FJ9WL; zTKTTV$4Un-Fq!yPTYmgKD@U6JTi#u1l?SUO9`(;#)Sl-|AWc;i2|X-6M~$e#BkrS0 zcH7|xRZ!0^`NK9f~imBqzNt<(Kl8H!VY|bM~QV%z+xXsJ@MY0&Y zov^~|zEsjz#R7|>+rE2=Tno`wPPtYJc?ZIJiF3vmlCVJ)=({(=4+-cX-MCgG;YZt{(7)se%B+HP-G_w_ z1y&8%V)n$R849{E#up6LLL1>lf4u#N=@P&*Blr;k05^qhaNxxs!K38mOF#?`Fv2h) z!3!=Ug3|AODcTQ13xJma0OmMIf`s|y0$yO!xk1NkXWW7uxxhPH%QXdN4@WfkJphg& z6{Lm<5NHI?auI#TP`ecRQ`3S~_pieO2GGQbJA(3SqF;em*%WuvHIEJ@qL!p~oi*=c zC#zL5>IGNT+#219AXu4gexCE4_M;N7_O{dUl@IYRQmyRDWUgd$(YGX|Z&K~5)*QF# zD#Bs*h=E=DLtZogdp2jgTW=Q@P0+Foo`3WZ{)1?g%fubVi2&Nk1%N?k0RVBci9`VC z0Iea&YIO&#PS6^LEHW3+>H@71$kM0Oyb5%K)+l5(OOcoXZ$N7dw1}4j+_;H>9?*OX zB_`T~U+e{~caT-24qAPn^&Wz@Cb}Xcfqu~Z03~vlgNXy6^%1hjboq#ZLC_k9td1#? zm%tEcO+ePGRPYyvL2DAS@(e+11hl3gYfp{DZ2Mkfk``50xW@Oagt2dW!H@Qa-q?}S zUl?+~DPHOtEZ+YpCwB?8cjjWitF9a`9mBTx#+8P3dFOavQTZN#L%AJpPJlVR7vmG( zvx_pnZ7xyuWm|X69ko&}IwQ-_%zcy}QzxEpL|%I#8RM!dp}=+`tHnY~%9Q8xG1lQ3 zU$|I~dD~8HQ3Qhy>62;^jU+A)aA+p(FEa@Mz&&Jv;Qts}tE+h#sy+aqgi8jhSpdL{ z0RGSP$!PHQO%5}b29vD;wtU3-oD@L0U2yiQpKH1rl5JHDb_N~FrwB`)Ga2npf$cV* z%(H1u06`U*w1ta-?QG93wbs4|YHxWtcN;yHSL^=PrF37Kn39Yb4Iq`kA#=n8FeLFm zDFyaIRy z@Cx7+z$@^t3LHT#0CL!ma|Hj>m`MU1!Ar!WF00uUg3{v0O)uW99Nak|akWoq6>Q2MX=Cr&z! zxodB(#gt_2vtmi9D$P_jjMqLn33ZQDX&225Sn{R)2PwZ&Ug26lQ~B*H$I8l&4@vn1qa zy-)mNpTBGDAwBtWR)vUt%&|85z|}YiagRbmwy2HEol7!6b2kM()Y+f?+wGO708f>kng96FrwpE)z`TM`@WQ3N)ya zk&8?w&2N4H%6v^Ss+m+eG=r&iM1-y}@=@Mj_UH3Mu;<6Dlg|_fOZSiks?r8G`VFwV_KHSweODXby4)5{3aU!eca1g^ zOnD1;^6d%Ma%2jWZ=ou`Yo{~;1oBInt5bt=nc*8AqYYu$*_H)-R&mH$w#tj$Zjc{@vjdY5MrO zLbbU!b5pZCENaWINf!Isu8}SJh3OORItguXX|Y0;iMO9}>WBY#>$@_0a z`VcUHn80HFw}QEj<`YqbjL0qB)m%C zSF|(sEXeTJ0X)M}=$tw7^$oHfqvDbtgn5wx%D7M;f|P*T`Crd`{Cm6tcm?nZ;1$3t zfL8#o0A2yS0(b@ft_pwyd-0LJe+;($yB0D&Uw8%Z3g8vMD}Yx3uK->FyaIRy{;9x! zM*9Azvz@~J5a=N*-k?yX>+^~=4#KVV0^5~+kB!I4eiMb43n|_W)@^UDE;Jq7jw8|Y zX%YFmMfxI@whqXRm8)s?F1$#~RE5Du`tXsy|D3b;Um|^> zDgQpF4*`cFeMqoHZVPngP5Ok~o3SO1iZr-s+FyaIRy@Cx7+z$@@KRsbLJ!^ivZ3g8vMD}Yx3 zuK->FyaIRy@Cy9@q`*HyehRSv>4JrYeJQi3xgYlNL9?;Xqi*mo>czryrL;@lYG8(m zT;ZbyC_P>^rtjZ$CzN%*R^>$e-9moNA$O-E}w@ vqS~*r{^DcB{O9zf-G84khM&>*e>bB~ 0 + + let hres = ChainFileHandle.init(FixtureFile, {}) + check hres.isOk() + let handle = hres.get() + check: + handle.head.isSome() + handle.tail.isSome() + let + head = handle.head.get() + tail = handle.tail.get() + headRoot = withBlck(head.blck): forkyBlck.root + tailRoot = withBlck(tail.blck): forkyBlck.root + check: + head.blob.isSome() + tail.blob.isSome() + headRoot == Block0Root + tailRoot == Block2Root + len(head.blob.get()) == Block0BlobsCount + len(tail.blob.get()) == Block2BlobsCount + let cres = close(handle) + check cres.isOk() + + test "Auto check/repair test (missing footer)": + let + hiLimit = len(fixtureData) - 1 + loLimit = len(fixtureData) - sizeof(ChainFileFooter) + var counter = 1 + + for size in countdown(hiLimit, loLimit): + let tres = doAutoCheckRepairTest(counter, size) + check tres.isOk() + let adata = tres.get() + check01(adata) + inc(counter) + + test "Auto check/repair test (missing last chunk)": + var size = len(fixtureData) + + block: + size -= onDiskChunkSize(Block2Blob2ChunkSize) + let tres = doAutoCheckRepairTest(1, size) + check tres.isOk() + let adata = tres.get() + check01(adata) + + block: + size -= onDiskChunkSize(Block2Blob1ChunkSize) + let tres = doAutoCheckRepairTest(2, size) + check tres.isOk() + let adata = tres.get() + check01(adata) + + block: + size -= onDiskChunkSize(Block2Blob0ChunkSize) + let tres = doAutoCheckRepairTest(3, size) + check tres.isOk() + let adata = tres.get() + check01(adata) + + block: + size -= onDiskChunkSize(Block2BlockChunkSize) + let tres = doAutoCheckRepairTest(4, size) + check tres.isOk() + let adata = tres.get() + check01(adata) + + block: + size -= onDiskChunkSize(Block1Blob2ChunkSize) + let tres = doAutoCheckRepairTest(5, size) + check tres.isOk() + let adata = tres.get() + check0(adata) + + block: + size -= onDiskChunkSize(Block1Blob1ChunkSize) + let tres = doAutoCheckRepairTest(6, size) + check tres.isOk() + let adata = tres.get() + check0(adata) + + block: + size -= onDiskChunkSize(Block1Blob0ChunkSize) + let tres = doAutoCheckRepairTest(7, size) + check tres.isOk() + let adata = tres.get() + check0(adata) + + block: + size -= onDiskChunkSize(Block1BlockChunkSize) + let tres = doAutoCheckRepairTest(8, size) + check tres.isOk() + let adata = tres.get() + check0(adata) + + block: + size -= onDiskChunkSize(Block0Blob0ChunkSize) + let tres = doAutoCheckRepairTest(9, size) + check tres.isOk() + let adata = tres.get() + check: + adata.data.head.isNone() + adata.data.tail.isNone() + adata.size == 0 + + block: + size -= onDiskChunkSize(Block0BlockChunkSize) + let tres = doAutoCheckRepairTest(10, size) + check tres.isOk() + let adata = tres.get() + check: + adata.data.head.isNone() + adata.data.tail.isNone() + adata.size == 0 + + test "Auto check/repair test (only header)": + var size = len(fixtureData) + + block: + size -= onDiskChunkSize(Block2Blob2ChunkSize) + let tres = doAutoCheckRepairTest(1, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check01(adata) + + block: + size -= onDiskChunkSize(Block2Blob1ChunkSize) + let tres = doAutoCheckRepairTest(2, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check01(adata) + + block: + size -= onDiskChunkSize(Block2Blob0ChunkSize) + let tres = doAutoCheckRepairTest(3, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check01(adata) + + block: + size -= onDiskChunkSize(Block2BlockChunkSize) + let tres = doAutoCheckRepairTest(4, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check01(adata) + + block: + size -= onDiskChunkSize(Block1Blob2ChunkSize) + let tres = doAutoCheckRepairTest(5, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check0(adata) + + block: + size -= onDiskChunkSize(Block1Blob1ChunkSize) + let tres = doAutoCheckRepairTest(6, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check0(adata) + + block: + size -= onDiskChunkSize(Block1Blob0ChunkSize) + let tres = doAutoCheckRepairTest(7, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check0(adata) + + block: + size -= onDiskChunkSize(Block1BlockChunkSize) + let tres = doAutoCheckRepairTest(8, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check0(adata) + + block: + size -= onDiskChunkSize(Block0Blob0ChunkSize) + let tres = doAutoCheckRepairTest(9, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check: + adata.data.head.isNone() + adata.data.tail.isNone() + adata.size == 0 + + block: + size -= onDiskChunkSize(Block0BlockChunkSize) + let tres = doAutoCheckRepairTest(10, size + sizeof(ChainFileHeader)) + check tres.isOk() + let adata = tres.get() + check: + adata.data.head.isNone() + adata.data.tail.isNone() + adata.size == 0 + + test "Auto check/repair test (missing data)": + let + limit1 = Block0FullSize + Block1FullSize + Block2FullSize + limit2 = Block0FullSize + Block1FullSize + limit3 = Block0FullSize + var + size = len(fixtureData) + counter = 1 + + while size > 0: + size = max(0, size - 4096) + let tres = doAutoCheckRepairTest(counter, size) + check tres.isOk() + let adata = tres.get() + if (size < limit1) and (size >= limit2): + check01(adata) + elif (size < limit2) and (size >= limit3): + check0(adata) + else: + check: + adata.data.head.isNone() + adata.data.tail.isNone() + adata.size == 0 + inc(counter) diff --git a/tests/test_block_processor.nim b/tests/test_block_processor.nim index 9f699ffe1..67a392c66 100644 --- a/tests/test_block_processor.nim +++ b/tests/test_block_processor.nim @@ -55,8 +55,9 @@ suite "Block processor" & preset(): b1 = addTestBlock(state[], cache).phase0Data b2 = addTestBlock(state[], cache).phase0Data getTimeFn = proc(): BeaconTime = b2.message.slot.start_beacon_time() + batchVerifier = BatchVerifier.new(rng, taskpool) processor = BlockProcessor.new( - false, "", "", rng, taskpool, consensusManager, + false, "", "", batchVerifier, consensusManager, validatorMonitor, blobQuarantine, getTimeFn) processorFut = processor.runQueueProcessingLoop() diff --git a/tests/test_blockchain_dag.nim b/tests/test_blockchain_dag.nim index 33485f365..70e6baadc 100644 --- a/tests/test_blockchain_dag.nim +++ b/tests/test_blockchain_dag.nim @@ -256,39 +256,41 @@ suite "Block pool processing" & preset(): # move to specific block var cache = StateCache() check: - dag.updateState(tmpState[], bs1, false, cache) + dag.updateState(tmpState[], bs1, false, cache, dag.updateFlags) tmpState[].latest_block_root == b1Add[].root getStateField(tmpState[], slot) == bs1.slot # Skip slots check: - dag.updateState(tmpState[], bs1_3, false, cache) # skip slots + dag.updateState(tmpState[], bs1_3, false, cache, dag.updateFlags) # skip slots tmpState[].latest_block_root == b1Add[].root getStateField(tmpState[], slot) == bs1_3.slot # Move back slots, but not blocks check: dag.updateState( - tmpState[], dag.parent(bs1_3.bid).expect("block").atSlot(), false, cache) + tmpState[], dag.parent(bs1_3.bid).expect("block").atSlot(), false, + cache, dag.updateFlags) tmpState[].latest_block_root == b1Add[].parent.root getStateField(tmpState[], slot) == b1Add[].parent.slot # Move to different block and slot check: - dag.updateState(tmpState[], bs2_3, false, cache) + dag.updateState(tmpState[], bs2_3, false, cache, dag.updateFlags) tmpState[].latest_block_root == b2Add[].root getStateField(tmpState[], slot) == bs2_3.slot # Move back slot and block check: - dag.updateState(tmpState[], bs1, false, cache) + dag.updateState(tmpState[], bs1, false, cache, dag.updateFlags) tmpState[].latest_block_root == b1Add[].root getStateField(tmpState[], slot) == bs1.slot # Move back to genesis check: dag.updateState( - tmpState[], dag.parent(bs1.bid).expect("block").atSlot(), false, cache) + tmpState[], dag.parent(bs1.bid).expect("block").atSlot(), false, cache, + dag.updateFlags) tmpState[].latest_block_root == b1Add[].parent.root getStateField(tmpState[], slot) == b1Add[].parent.slot @@ -500,7 +502,7 @@ suite "chain DAG finalization tests" & preset(): check: updateState( dag, tmpStateData[], dag.head.atSlot(dag.head.slot).toBlockSlotId().expect("not nil"), - false, cache) + false, cache, dag.updateFlags) check: dag.head.slot.epoch in cache.shuffled_active_validator_indices @@ -623,7 +625,8 @@ suite "chain DAG finalization tests" & preset(): while cur != nil: # Go all the way to dag.finalizedHead assign(tmpStateData[], dag.headState) check: - dag.updateState(tmpStateData[], cur.bid.atSlot(), false, cache) + dag.updateState(tmpStateData[], cur.bid.atSlot(), false, cache, + dag.updateFlags) dag.getForkedBlock(cur.bid).get().phase0Data.message.state_root == getStateRoot(tmpStateData[]) getStateRoot(tmpStateData[]) == hash_tree_root( diff --git a/tests/test_sync_manager.nim b/tests/test_sync_manager.nim index 5d7fa83cf..3071aa92d 100644 --- a/tests/test_sync_manager.nim +++ b/tests/test_sync_manager.nim @@ -1059,9 +1059,12 @@ suite "SyncManager test suite": req1.contains(Slot(15)) == false test "[SyncQueue] checkResponse() test": - let chain = createChain(Slot(10), Slot(20)) - let r1 = SyncRequest[SomeTPeer](slot: Slot(11), count: 1'u64) - let r21 = SyncRequest[SomeTPeer](slot: Slot(11), count: 2'u64) + let + chain = createChain(Slot(10), Slot(20)) + r1 = SyncRequest[SomeTPeer](slot: Slot(11), count: 1'u64) + r21 = SyncRequest[SomeTPeer](slot: Slot(11), count: 2'u64) + r3 = SyncRequest[SomeTPeer](slot: Slot(11), count: 3'u64) + let slots = mapIt(chain, it[].slot) check: @@ -1083,12 +1086,39 @@ suite "SyncManager test suite": checkResponse(r21, @[slots[2], slots[3]]) == false checkResponse(r21, @[slots[3]]) == false - test "[SyncManager] groupBlobs() test": - var blocks = createChain(Slot(10), Slot(15)) - var blobs = createBlobs(blocks, @[Slot(11), Slot(11), Slot(12), Slot(14)]) + checkResponse(r21, @[slots[1], slots[1]]) == false + checkResponse(r21, @[slots[2], slots[2]]) == false - let req = SyncRequest[SomeTPeer](slot: Slot(10)) - let groupedRes = groupBlobs(req, blocks, blobs) + checkResponse(r3, @[slots[1]]) == true + checkResponse(r3, @[slots[2]]) == true + checkResponse(r3, @[slots[3]]) == true + checkResponse(r3, @[slots[1], slots[2]]) == true + checkResponse(r3, @[slots[1], slots[3]]) == true + checkResponse(r3, @[slots[2], slots[3]]) == true + checkResponse(r3, @[slots[1], slots[3], slots[2]]) == false + checkResponse(r3, @[slots[2], slots[3], slots[1]]) == false + checkResponse(r3, @[slots[3], slots[2], slots[1]]) == false + checkResponse(r3, @[slots[3], slots[1]]) == false + checkResponse(r3, @[slots[3], slots[2]]) == false + checkResponse(r3, @[slots[2], slots[1]]) == false + + checkResponse(r3, @[slots[1], slots[1], slots[1]]) == false + checkResponse(r3, @[slots[1], slots[2], slots[2]]) == false + checkResponse(r3, @[slots[1], slots[3], slots[3]]) == false + checkResponse(r3, @[slots[2], slots[3], slots[3]]) == false + checkResponse(r3, @[slots[1], slots[1], slots[1]]) == false + checkResponse(r3, @[slots[2], slots[2], slots[2]]) == false + checkResponse(r3, @[slots[3], slots[3], slots[3]]) == false + checkResponse(r3, @[slots[1], slots[1]]) == false + checkResponse(r3, @[slots[2], slots[2]]) == false + checkResponse(r3, @[slots[3], slots[3]]) == false + + test "[SyncManager] groupBlobs() test": + var + blocks = createChain(Slot(10), Slot(15)) + blobs = createBlobs(blocks, @[Slot(11), Slot(11), Slot(12), Slot(14)]) + + let groupedRes = groupBlobs(blocks, blobs) check: groupedRes.isOk() @@ -1118,7 +1148,7 @@ suite "SyncManager test suite": let block17 = newClone ForkedSignedBeaconBlock(kind: ConsensusFork.Deneb) block17[].denebData.message.slot = Slot(17) blocks.add(block17) - let groupedRes2 = groupBlobs(req, blocks, blobs) + let groupedRes2 = groupBlobs(blocks, blobs) check: groupedRes2.isOk() @@ -1130,7 +1160,7 @@ suite "SyncManager test suite": let blob18 = new (ref BlobSidecar) blob18[].signed_block_header.message.slot = Slot(18) blobs.add(blob18) - let groupedRes3 = groupBlobs(req, blocks, blobs) + let groupedRes3 = groupBlobs(blocks, blobs) check: groupedRes3.isErr()